代码提交
This commit is contained in:
parent
005ce674db
commit
476b9f79cb
|
|
@ -1,2 +1,3 @@
|
|||
export * from './auth'
|
||||
export * from './user'
|
||||
export * from './modules/auth'
|
||||
export * from './modules/user'
|
||||
export * from './modules/workTicket'
|
||||
|
|
@ -17,9 +17,13 @@ export function bindPhone(phone, smsCode) {
|
|||
}
|
||||
|
||||
export function getUserList(params) {
|
||||
return get('/user/list', params)
|
||||
return get('/system/user/list', params)
|
||||
}
|
||||
|
||||
export function getUserDetail(id) {
|
||||
return get(`/user/detail/${id}`)
|
||||
}
|
||||
|
||||
export function getUserInfo() {
|
||||
return get('/system/user/getInfo')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,199 @@
|
|||
import { post, get, del, put, uploadFile } from '../request'
|
||||
|
||||
/**
|
||||
* 新增工作票申请
|
||||
* @param {Object} data - 工作票数据
|
||||
* @param {Number} data.projectId - 所属项目ID(必填)
|
||||
* @param {String} data.workLocation - 作业地点
|
||||
* @param {Number} data.supervisorId - 作业负责人ID
|
||||
* @param {String} data.supervisorName - 作业负责人姓名
|
||||
* @param {String} data.supervisorPosition - 作业负责人职位
|
||||
* @param {String} data.workContent - 作业内容
|
||||
* @param {String} data.riskType - 风险类型(如:高风险、中风险、低风险)
|
||||
* @param {String} data.workStartTime - 作业开始时间(格式:yyyy-MM-dd HH:mm:ss)
|
||||
* @param {String} data.workEndTime - 作业结束时间(格式:yyyy-MM-dd HH:mm:ss)
|
||||
* @param {Array<String>} data.safetyMeasuresList - 安全措施列表
|
||||
* @param {Array<Object>} data.qualificationList - 作业班成员资质列表
|
||||
* @param {String} data.needMonitoringCamera - 是否需申领移动监控球机("0"否,"1"是)
|
||||
* @param {Number} data.cameraApplicationId - 监控球机申请ID(如果需要监控球机时填写)
|
||||
* @param {String} data.remark - 备注
|
||||
* @returns {Promise} 返回工作票ID
|
||||
*/
|
||||
export function createWorkTicket(data) {
|
||||
return post('/manage/contractor/workTicket', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 出入证申请
|
||||
* @param {Object} data - 出入证申请数据
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function applyAccessPermit(data) {
|
||||
return post('/manage/contractor/accessPermit', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增工作计划
|
||||
* @param {Object} data - 工作计划数据
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function createWorkPlan(data) {
|
||||
return post('/manage/contractor/workPlan', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 球机申领新增接口
|
||||
* @param {Object} data - 球机申领数据
|
||||
* @param {Number} data.projectId - 项目ID(必填)
|
||||
* @param {Number} data.needCameraCnt - 申领数量(必填,必须大于0)
|
||||
* @param {String} data.installationLocation - 安装位置(必填)
|
||||
* @param {String} data.contactPerson - 联系人(必填)
|
||||
* @param {String} data.contactPhone - 联系方式(必填)
|
||||
* @param {String} data.remark - 备注(可选)
|
||||
* @returns {Promise} 返回申领单ID
|
||||
*/
|
||||
export function createCameraApplication(data) {
|
||||
return post('/manage/project/cameraApplication', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询工作计划列表
|
||||
* @param {Object} params - 查询参数
|
||||
* @param {Number} params.pageNum - 页码(可选)
|
||||
* @param {Number} params.pageSize - 每页数量(可选)
|
||||
* @param {String} params.status - 状态(可选)
|
||||
* @param {Number} params.projectId - 项目ID(可选)
|
||||
* @returns {Promise} 返回工作计划列表 { total: number, rows: array }
|
||||
*/
|
||||
export function getWorkPlanList(params) {
|
||||
return get('/manage/contractor/workPlan/list', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除工作计划
|
||||
* @param {Number|String|Array<Number>|Array<String>} projectIds - 项目ID,可以是单个ID、ID数组或逗号分隔的字符串
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function deleteWorkPlan(projectIds) {
|
||||
// 处理不同的输入格式
|
||||
let ids = projectIds
|
||||
if (Array.isArray(projectIds)) {
|
||||
ids = projectIds.join(',')
|
||||
}
|
||||
return del(`/manage/contractor/workPlan/${ids}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交工作计划
|
||||
* @param {Number|String} projectId - 项目ID(必填)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function submitWorkPlan(projectId) {
|
||||
return put(`/manage/contractor/workPlan/submit/${projectId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param {String} filePath - 文件路径(本地临时文件路径)
|
||||
* @param {String} name - 文件对应的 key,默认为 'file'
|
||||
* @param {Object} formData - 额外的表单数据
|
||||
* @param {Object} options - 其他配置选项
|
||||
* @returns {Promise<{name: string, url: string}>} 返回上传后的文件信息,包含 name(文件名)和 url(文件访问地址)
|
||||
*/
|
||||
export function uploadFileApi(filePath, name = 'file', formData = {}, options = {}) {
|
||||
return uploadFile('/file/upload', filePath, name, formData, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询风险管控卡模板列表
|
||||
* @param {Object} params - 查询参数(可选)
|
||||
* @returns {Promise} 返回风险管控卡模板列表
|
||||
*/
|
||||
export function getRiskCardTemplateList(params = {}) {
|
||||
return get('/manage/logistics/riskCard/template/list', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取风险管控卡模板详细信息
|
||||
* @param {Number|String} templateId - 模板ID(必填)
|
||||
* @returns {Promise} 返回风险管控卡模板详细信息
|
||||
*/
|
||||
export function getRiskCardTemplateDetail(templateId) {
|
||||
return get(`/manage/logistics/riskCard/template/${templateId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作计划详细信息
|
||||
* @param {Number|String} projectId - 项目ID(必填)
|
||||
* @returns {Promise} 返回工作计划详细信息
|
||||
*/
|
||||
export function getWorkPlanDetail(projectId) {
|
||||
return get(`/manage/contractor/workPlan/${projectId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作票详细信息
|
||||
* @param {Number|String} ticketId - 工作票ID(必填)
|
||||
* @returns {Promise} 返回工作票详细信息
|
||||
*/
|
||||
export function getWorkTicketDetail(ticketId) {
|
||||
return get(`/manage/contractor/workTicket/${ticketId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交风险管控卡监理审核
|
||||
* @param {Object} data - 风险管控卡数据
|
||||
* @param {Number} data.ticketId - 工作票ID(必填)
|
||||
* @param {Number} data.templateId - 模板ID(必填)
|
||||
* @param {String} data.ticketNumber - 票证编号(必填)
|
||||
* @param {String} data.operatingUnit - 所属单位(必填)
|
||||
* @param {String} data.workContent - 工作内容(必填)
|
||||
* @param {String} data.supervisorName - 工作负责人姓名(必填)
|
||||
* @param {String} data.supervisorPosition - 工作负责人职位
|
||||
* @param {String} data.contactMethod - 联系方式
|
||||
* @param {String} data.inspectionTime - 检查时间(格式:yyyy-MM-ddTHH:mm)
|
||||
* @param {Array<Object>} data.checkItems - 检查项列表
|
||||
* @param {Number} data.checkItems[].templateItemId - 模板项ID
|
||||
* @param {String} data.checkItems[].itemDescription - 检查项描述
|
||||
* @param {String} data.checkItems[].checkResult - 检查结果
|
||||
* @param {Number} data.checkItems[].sortOrder - 排序顺序
|
||||
* @param {Array<String>} data.attachmentList - 附件URL列表
|
||||
* @returns {Promise} 返回风险管控卡ID(cardId)
|
||||
*/
|
||||
export function submitRiskControlCard(data) {
|
||||
return post('/manage/contractor/riskControlCard', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交工作票
|
||||
* @param {Number|String} ticketId - 工作票ID(必填)
|
||||
* @param {Number|String} cardId - 风险管控卡ID(可选,高等风险时必填)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function submitWorkTicket(ticketId, cardId = null) {
|
||||
let url = `/manage/contractor/workTicket/submit/${ticketId}`;
|
||||
if (cardId) {
|
||||
url += `?cardId=${cardId}`;
|
||||
}
|
||||
return put(url)
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交工作票(承包商接口)
|
||||
* @param {Number|String} ticketId - 工作票ID(必填)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function submitWorkTicketForContractor(ticketId) {
|
||||
return put(`/manage/contractor/workTicket/submit/${ticketId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交实施
|
||||
* @param {Number|String} projectId - 项目ID(必填)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function submitImplementation(projectId) {
|
||||
return put(`/manage/contractor/projectImplementation/submitImplementation?projectId=${projectId}`)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,21 +1,28 @@
|
|||
import { useUserStore } from '@/store/user'
|
||||
|
||||
const BASE_URL = 'https://api.example.com'
|
||||
// 根据平台配置不同的基础URL
|
||||
// H5 开发环境使用代理路径 /api,通过 vite 代理解决跨域问题
|
||||
// H5 生产环境和小程序、App 使用完整URL
|
||||
let BASE_URL = '/api'
|
||||
|
||||
// #ifdef H5
|
||||
|
||||
// #endif
|
||||
|
||||
const requestInterceptor = (config) => {
|
||||
const userStore = useUserStore()
|
||||
|
||||
if (config.header) {
|
||||
config.header = {
|
||||
...config.header,
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': userStore.token ? `Bearer ${userStore.token}` : ''
|
||||
}
|
||||
} else {
|
||||
config.header = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': userStore.token ? `Bearer ${userStore.token}` : ''
|
||||
// 初始化 header 对象
|
||||
if (!config.header) {
|
||||
config.header = {}
|
||||
}
|
||||
|
||||
// 设置 Content-Type
|
||||
config.header['Content-Type'] = config.header['Content-Type'] || 'application/json'
|
||||
|
||||
// 如果有 token,添加 authorization header
|
||||
if (userStore.token) {
|
||||
config.header['authorization'] = `Bearer ${userStore.token}`
|
||||
}
|
||||
|
||||
return config
|
||||
|
|
@ -25,11 +32,11 @@ const responseInterceptor = (response) => {
|
|||
const { statusCode, data } = response
|
||||
|
||||
if (statusCode === 200) {
|
||||
if (data.code === 0 || data.success) {
|
||||
return data.data || data.result
|
||||
if (data.code === 0 || data.code === 200 || data.success) {
|
||||
return data.data || data.result || data
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: data.message || '请求失败',
|
||||
title: data.msg || data.message || '请求失败',
|
||||
icon: 'none'
|
||||
})
|
||||
return Promise.reject(data)
|
||||
|
|
@ -81,10 +88,13 @@ function request(options) {
|
|||
url: url.startsWith('http') ? url : `${BASE_URL}${url}`,
|
||||
method,
|
||||
data,
|
||||
header: requestInterceptor({ header }),
|
||||
header,
|
||||
timeout: 15000
|
||||
}
|
||||
|
||||
// 通过拦截器处理 header
|
||||
requestInterceptor(config)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (loading) {
|
||||
uni.showLoading({
|
||||
|
|
@ -96,8 +106,17 @@ function request(options) {
|
|||
uni.request({
|
||||
...config,
|
||||
success: (res) => {
|
||||
try {
|
||||
const result = responseInterceptor(res)
|
||||
// 如果 result 是 Promise,需要正确处理
|
||||
if (result instanceof Promise) {
|
||||
result.then(resolve).catch(reject)
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.showToast({
|
||||
|
|
@ -160,4 +179,112 @@ export function patch(url, data, options) {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* @param {String} url - 上传接口地址
|
||||
* @param {String} filePath - 文件路径(本地临时文件路径)
|
||||
* @param {String} name - 文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容
|
||||
* @param {Object} formData - HTTP 请求中其他额外的 form data
|
||||
* @param {Object} options - 其他配置选项
|
||||
* @param {Boolean} options.loading - 是否显示加载提示,默认 true
|
||||
* @param {String} options.loadingText - 加载提示文字,默认 '上传中...'
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function uploadFile(url, filePath, name = 'file', formData = {}, options = {}) {
|
||||
const { loading = true, loadingText = '上传中...' } = options
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 构建完整的 URL
|
||||
const fullUrl = url.startsWith('http') ? url : `${BASE_URL}${url}`
|
||||
|
||||
// 构建请求头
|
||||
const header = {}
|
||||
if (userStore.token) {
|
||||
header['authorization'] = `Bearer ${userStore.token}`
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (loading) {
|
||||
uni.showLoading({
|
||||
title: loadingText,
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
|
||||
uni.uploadFile({
|
||||
url: fullUrl,
|
||||
filePath: filePath,
|
||||
name: name,
|
||||
formData: formData,
|
||||
header: header,
|
||||
success: (res) => {
|
||||
try {
|
||||
// uni.uploadFile 返回的是字符串,需要解析
|
||||
const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
|
||||
|
||||
if (res.statusCode === 200) {
|
||||
if (data.code === 0 || data.code === 200 || data.success) {
|
||||
resolve(data.data || data.result || data)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: data.msg || data.message || '上传失败',
|
||||
icon: 'none'
|
||||
})
|
||||
reject(data)
|
||||
}
|
||||
} else if (res.statusCode === 401) {
|
||||
uni.showToast({
|
||||
title: '登录已过期,请重新登录',
|
||||
icon: 'none'
|
||||
})
|
||||
userStore.clearUser()
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
}, 1500)
|
||||
reject(res)
|
||||
} else if (res.statusCode === 403) {
|
||||
uni.showToast({
|
||||
title: '没有权限访问',
|
||||
icon: 'none'
|
||||
})
|
||||
reject(res)
|
||||
} else if (res.statusCode >= 500) {
|
||||
uni.showToast({
|
||||
title: '服务器错误,请稍后重试',
|
||||
icon: 'none'
|
||||
})
|
||||
reject(res)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '上传失败',
|
||||
icon: 'none'
|
||||
})
|
||||
reject(res)
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: '上传响应解析失败',
|
||||
icon: 'none'
|
||||
})
|
||||
reject(error)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.showToast({
|
||||
title: '上传失败,请检查网络',
|
||||
icon: 'none'
|
||||
})
|
||||
reject(err)
|
||||
},
|
||||
complete: () => {
|
||||
if (loading) {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default request
|
||||
|
|
|
|||
|
|
@ -43,7 +43,13 @@
|
|||
"minified": true,
|
||||
"postcss": true
|
||||
},
|
||||
"usingComponents": true
|
||||
"usingComponents": true,
|
||||
"requiredPrivateInfos": [],
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "您的位置信息将用于小程序位置接口的效果展示"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mp-alipay": {
|
||||
"usingComponents": true
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<view class="FlexBox TopBox">
|
||||
<view class="SelectBox">
|
||||
<u-select :current="TypeValue" :options="TypeList" placeholder="请选择工单类型" size="large" showOptionsLabel
|
||||
@update:current="TypeValue = $event"></u-select>
|
||||
@update:current="handleTypeChange($event)"></u-select>
|
||||
</view>
|
||||
<view class="BtnBox">
|
||||
<u-button type="primary" text="查询" @click="HandleNewAdd">新建工单</u-button>
|
||||
|
|
@ -12,31 +12,32 @@
|
|||
|
||||
|
||||
</view>
|
||||
<view class="ListBox">
|
||||
<u-virtual-list :list-data="dataSource" :item-height="200" height="100%">
|
||||
<template #default="{ item, index }">
|
||||
<view class="CardBox">
|
||||
<scroll-view class="ListBox" scroll-y>
|
||||
<view class="CardBox" v-for="(item, index) in dataSource" :key="index">
|
||||
<view class="FlexBox">
|
||||
<view class="Title">{{ item.name }}</view>
|
||||
<view class="DetailBtn">详情</view>
|
||||
<view class="Title">{{ item.projectName || '未命名项目' }}</view>
|
||||
<view class="DetailBtn" @click="handleDetail(item)">详情</view>
|
||||
</view>
|
||||
<view class="CodeTxt">项目编号:{{ item.projectCode }}</view>
|
||||
<!-- <view class="CodeTxt">作业地点:{{ item.workLocation }}</view>
|
||||
<view class="CodeTxt">作业负责人:{{ item.supervisorName || '未设置' }}</view> -->
|
||||
<view class="TagBox">
|
||||
<u-tag text="代填工作票" shape="circle"></u-tag>
|
||||
<!-- <u-tag :text="getStatusText(item.projectStatus)" shape="circle"></u-tag> -->
|
||||
<u-tag :text="item.draftStatusText" shape="circle"></u-tag>
|
||||
</view>
|
||||
<view class="BtnList">
|
||||
<u-button text="修改" plain color="#2979ff" size="small"></u-button>
|
||||
<u-button text="撤回" plain color="#ff9900" size="small"></u-button>
|
||||
<u-button text="删除" plain color="#fa3534" size="small"></u-button>
|
||||
<u-button text="删除" plain color="#fa3534" size="small" @click="handleDelete(item, index)"></u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-virtual-list>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { getWorkPlanList, deleteWorkPlan } from '@/api/modules/workTicket'
|
||||
|
||||
const TypeValue = ref('1') // 工单类型
|
||||
// 类型列表
|
||||
const TypeList = ref([
|
||||
|
|
@ -47,15 +48,92 @@ const TypeList = ref([
|
|||
{ name: '已撤回', id: '5' },
|
||||
])
|
||||
|
||||
const dataSource = ref([
|
||||
{ id: 1, name: '工单1', projectCode: '123456' },
|
||||
{ id: 2, name: '工单2', projectCode: '123457' },
|
||||
{ id: 3, name: '工单3', projectCode: '123458' },
|
||||
{ id: 4, name: '工单4', projectCode: '123459' },
|
||||
{ id: 5, name: '工单5', projectCode: '123460' },
|
||||
{ id: 6, name: '工单6', projectCode: '123461' },
|
||||
{ id: 7, name: '工单7', projectCode: '123462' },
|
||||
])
|
||||
const dataSource = ref([])
|
||||
const total = ref(0) // 总条数
|
||||
|
||||
// 获取状态文本
|
||||
// 项目状态:0草稿,1已提交,2进行中,3已完成,4已取消
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
'0': '草稿',
|
||||
'1': '已提交',
|
||||
'2': '进行中',
|
||||
'3': '已完成',
|
||||
'4': '已取消'
|
||||
}
|
||||
return statusMap[status] || '未知状态'
|
||||
}
|
||||
|
||||
// 判断是否显示修改按钮
|
||||
// 待填写工作票、已驳回:显示修改按钮
|
||||
const shouldShowEditButton = (item) => {
|
||||
const status = item.draftStatusText || ''
|
||||
return status === '待填写工作票' || status === '已驳回'
|
||||
}
|
||||
|
||||
// 判断是否显示撤回按钮
|
||||
// 待申领监控球机、待审核:只显示撤回按钮
|
||||
const shouldShowWithdrawButton = (item) => {
|
||||
const status = item.draftStatusText || ''
|
||||
return status === '待申领监控球机' || status === '待审核'
|
||||
}
|
||||
|
||||
// 判断是否显示删除按钮
|
||||
// 待填写工作票、已驳回:显示删除按钮
|
||||
const shouldShowDeleteButton = (item) => {
|
||||
const status = item.draftStatusText || ''
|
||||
return status === '待填写工作票' || status === '已驳回'
|
||||
}
|
||||
|
||||
// 查询工作计划列表
|
||||
const fetchWorkPlanList = async () => {
|
||||
try {
|
||||
const params = {
|
||||
pageNum: 1,
|
||||
pageSize: 1000
|
||||
}
|
||||
// 根据选择的类型添加筛选条件
|
||||
if (TypeValue.value === '3') {
|
||||
params.draftStatusText = '草稿' // 草稿
|
||||
} else if (TypeValue.value === '4') {
|
||||
params.draftStatusText = '待审核' // 待审核
|
||||
} else if (TypeValue.value === '5') {
|
||||
params.draftStatusText = '已撤回' // 已撤回
|
||||
}
|
||||
|
||||
const result = await getWorkPlanList(params)
|
||||
// 根据返回的数据结构处理:{ total, rows }
|
||||
if (result && result.rows) {
|
||||
dataSource.value = result.rows
|
||||
total.value = result.total || 0
|
||||
} else if (Array.isArray(result)) {
|
||||
dataSource.value = result
|
||||
total.value = result.length
|
||||
} else if (result && result.list) {
|
||||
dataSource.value = result.list
|
||||
total.value = result.total || result.list.length
|
||||
} else if (result && result.records) {
|
||||
dataSource.value = result.records
|
||||
total.value = result.total || result.records.length
|
||||
} else if (result && result.data) {
|
||||
dataSource.value = result.data
|
||||
total.value = result.total || result.data.length
|
||||
} else {
|
||||
dataSource.value = []
|
||||
total.value = 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('查询工作计划列表失败:', error)
|
||||
dataSource.value = []
|
||||
total.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
// 监听类型变化,重新查询
|
||||
const handleTypeChange = (value) => {
|
||||
TypeValue.value = value
|
||||
fetchWorkPlanList()
|
||||
}
|
||||
|
||||
// 跳转新建工单
|
||||
const HandleNewAdd = () => {
|
||||
|
|
@ -64,6 +142,85 @@ const HandleNewAdd = () => {
|
|||
})
|
||||
}
|
||||
|
||||
// 跳转到详情页
|
||||
const handleDetail = (item) => {
|
||||
const projectId = item.projectId || item.id
|
||||
if (!projectId) {
|
||||
uni.showToast({
|
||||
title: '项目ID不存在',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
// 获取工作票ID,支持 ticketIds 或 ticketId 字段
|
||||
const ticketId = item.ticketIds || item.ticketId
|
||||
// 构建跳转URL
|
||||
let url = `/pages/WorkOrderDetails/index?projectId=${projectId}`
|
||||
if (ticketId) {
|
||||
// 如果 ticketIds 是数组,取第一个;如果是单个值,直接使用
|
||||
const ticketIdValue = Array.isArray(ticketId) ? ticketId[0] : ticketId
|
||||
url += `&workTicketId=${ticketIdValue}`
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: url
|
||||
})
|
||||
}
|
||||
|
||||
// 删除工作计划
|
||||
const handleDelete = async (item, index) => {
|
||||
try {
|
||||
// 确认删除
|
||||
const res = await new Promise((resolve) => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: `确定要删除项目"${item.projectName || '未命名项目'}"吗?`,
|
||||
confirmText: '删除',
|
||||
confirmColor: '#fa3534',
|
||||
success: (result) => {
|
||||
resolve(result.confirm)
|
||||
},
|
||||
fail: () => {
|
||||
resolve(false)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (!res) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取项目ID,优先使用 projectId,如果没有则使用 id
|
||||
const projectId = item.projectId || item.id
|
||||
if (!projectId) {
|
||||
uni.showToast({
|
||||
title: '项目ID不存在',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 调用删除接口
|
||||
await deleteWorkPlan(projectId)
|
||||
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 删除成功后,从列表中移除该项
|
||||
dataSource.value.splice(index, 1)
|
||||
total.value = total.value - 1
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
// 错误提示已在 request.js 的拦截器中处理
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时获取数据
|
||||
onMounted(() => {
|
||||
fetchWorkPlanList()
|
||||
})
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.FlexBox {
|
||||
|
|
@ -105,17 +262,15 @@ const HandleNewAdd = () => {
|
|||
padding: 20rpx 0px;
|
||||
margin-top: 20rpx;
|
||||
height: calc(100vh - 300rpx);
|
||||
overflow: hidden;
|
||||
.CardBox {
|
||||
width: calc(100% - 30rpx);
|
||||
height: calc(100% - 30rpx);
|
||||
min-height: 200rpx;
|
||||
margin: 0 auto;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08), 0 2rpx 4rpx rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 20rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 10rpx;
|
||||
overflow: auto;
|
||||
.Title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
|
|
@ -137,8 +292,15 @@ const HandleNewAdd = () => {
|
|||
margin-top: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
gap: 20rpx;
|
||||
|
||||
:deep(.u-button) {
|
||||
width: 80px !important;
|
||||
min-width: 60px !important;
|
||||
margin-left: 0 !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,7 +5,7 @@
|
|||
<view class="FormItem">
|
||||
<view class="FormLableBox mustBox">作业地点</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="allData.workLocation" placeholder="请输入作业地点" readonly></u-input>
|
||||
<u-input v-model="displayData.workLocation" placeholder="请输入作业地点" readonly></u-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
|
|
@ -13,11 +13,11 @@
|
|||
<view class="FormValueBox">
|
||||
<view class="date-range-box">
|
||||
<view class="date-item">
|
||||
<u-input v-model="allData.startTime" placeholder="开始时间" readonly></u-input>
|
||||
<u-input v-model="displayData.startTime" placeholder="开始时间" readonly></u-input>
|
||||
</view>
|
||||
<view class="date-separator">至</view>
|
||||
<view class="date-item">
|
||||
<u-input v-model="allData.endTime" placeholder="结束时间" readonly></u-input>
|
||||
<u-input v-model="displayData.endTime" placeholder="结束时间" readonly></u-input>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -35,9 +35,21 @@
|
|||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox mustBox">联系人+联系方式</view>
|
||||
<view class="FormLableBox mustBox">联系人</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="formData.linkman" placeholder="请输入联系人+联系方式"></u-input>
|
||||
<u-input v-model="formData.contactPerson" placeholder="请输入联系人"></u-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox mustBox">联系方式</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="formData.contactPhone" placeholder="请输入联系方式"></u-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox">备注</view>
|
||||
<view class="FormValueBox">
|
||||
<u-textarea v-model="formData.remark" placeholder="请输入备注(可选)"></u-textarea>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -46,7 +58,7 @@
|
|||
<script setup>
|
||||
import { generateGuid } from '@/utils/index.js';
|
||||
import dayjs from 'dayjs';
|
||||
import { ref, defineExpose } from 'vue'
|
||||
import { ref, onMounted, watch, defineExpose } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
allData: {
|
||||
|
|
@ -55,18 +67,110 @@ const props = defineProps({
|
|||
},
|
||||
})
|
||||
|
||||
const formData = ref({
|
||||
applyQuantity: '', // 申领数量
|
||||
installationSite: '', // 安装位置
|
||||
linkman: '', // 联系人+联系方式
|
||||
// 显示数据(作业地点和作业周期)
|
||||
const displayData = ref({
|
||||
workLocation: '', // 作业地点
|
||||
startTime: '', // 开始时间
|
||||
endTime: '', // 结束时间
|
||||
})
|
||||
|
||||
const formData = ref({
|
||||
applyQuantity: 1, // 申领数量
|
||||
installationSite: '', // 安装位置
|
||||
contactPerson: '', // 联系人
|
||||
contactPhone: '', // 联系方式
|
||||
remark: '', // 备注
|
||||
})
|
||||
|
||||
// 从 allData 中获取作业地点和作业周期
|
||||
const updateDisplayData = () => {
|
||||
// 优先从工作票(WorkNote)中获取
|
||||
const workNote = props.allData?.WorkNote;
|
||||
const basicsInfo = props.allData?.BasicsInfo;
|
||||
|
||||
// 获取作业地点:优先从 WorkNote.workLocation,其次从 BasicsInfo.SpecificAddress
|
||||
if (workNote?.workLocation) {
|
||||
displayData.value.workLocation = workNote.workLocation;
|
||||
} else if (basicsInfo?.SpecificAddress) {
|
||||
displayData.value.workLocation = basicsInfo.SpecificAddress;
|
||||
} else {
|
||||
displayData.value.workLocation = '';
|
||||
}
|
||||
|
||||
// 获取作业周期:优先从 WorkNote.period,其次从 BasicsInfo.period
|
||||
let period = null;
|
||||
if (workNote?.period && Array.isArray(workNote.period) && workNote.period.length >= 2) {
|
||||
period = workNote.period;
|
||||
} else if (basicsInfo?.period && Array.isArray(basicsInfo.period) && basicsInfo.period.length >= 2) {
|
||||
period = basicsInfo.period;
|
||||
}
|
||||
|
||||
if (period) {
|
||||
displayData.value.startTime = period[0] || '';
|
||||
displayData.value.endTime = period[1] || '';
|
||||
} else {
|
||||
displayData.value.startTime = '';
|
||||
displayData.value.endTime = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 从 allData 中恢复之前填写的数据
|
||||
const restoreFormData = (data) => {
|
||||
if (!data || Object.keys(data).length === 0) return;
|
||||
|
||||
if (data.applyQuantity !== undefined) formData.value.applyQuantity = data.applyQuantity;
|
||||
if (data.installationSite) formData.value.installationSite = data.installationSite;
|
||||
if (data.contactPerson) formData.value.contactPerson = data.contactPerson;
|
||||
if (data.contactPhone) formData.value.contactPhone = data.contactPhone;
|
||||
if (data.remark) formData.value.remark = data.remark;
|
||||
// 兼容旧数据格式(linkman字段)
|
||||
if (data.linkman && !data.contactPerson) {
|
||||
// 尝试解析旧格式:如果包含电话号码,尝试拆分
|
||||
const phoneMatch = data.linkman.match(/(\d{11}|\d{3,4}-\d{7,8})/);
|
||||
if (phoneMatch) {
|
||||
const phone = phoneMatch[0];
|
||||
formData.value.contactPerson = data.linkman.replace(phone, '').trim();
|
||||
formData.value.contactPhone = phone;
|
||||
} else {
|
||||
formData.value.contactPerson = data.linkman;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 监听 allData.ApplyForMachine 的变化,恢复表单数据
|
||||
watch(() => props.allData?.ApplyForMachine, (newData) => {
|
||||
if (newData && Object.keys(newData).length > 0) {
|
||||
restoreFormData(newData);
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 监听 allData.WorkNote 和 allData.BasicsInfo 的变化,更新显示数据
|
||||
watch(() => [props.allData?.WorkNote, props.allData?.BasicsInfo], () => {
|
||||
updateDisplayData();
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 数量变化事件
|
||||
const valChange = (val) => {
|
||||
console.log('申领数量变化:', val);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
getFormData() {
|
||||
return formData.value;
|
||||
}
|
||||
})
|
||||
|
||||
// 生命周期钩子函数
|
||||
onMounted(() => {
|
||||
// 更新显示数据(作业地点和作业周期)
|
||||
updateDisplayData();
|
||||
|
||||
// 组件挂载后,从 allData 中恢复数据
|
||||
if (props.allData?.ApplyForMachine && Object.keys(props.allData.ApplyForMachine).length > 0) {
|
||||
restoreFormData(props.allData.ApplyForMachine);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.BlueTxt {
|
||||
|
|
|
|||
|
|
@ -71,8 +71,16 @@
|
|||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, defineExpose } from "vue";
|
||||
import { ref, computed, onMounted, watch, defineExpose } from "vue";
|
||||
import dayjs from 'dayjs';
|
||||
import { getUserList } from '@/api';
|
||||
|
||||
const props = defineProps({
|
||||
allData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
// 地图实例
|
||||
let mapEntity = null;
|
||||
|
|
@ -97,18 +105,7 @@ const endDateMinTimestamp = computed(() => {
|
|||
|
||||
const showMemberPicker = ref(false); // 是否显示成员选择器
|
||||
//成员列表信息
|
||||
const MemberArr = ref([
|
||||
{
|
||||
id: "123456", // 成员ID
|
||||
name: "张三", // 成员姓名
|
||||
phone: "13800000000", // 成员手机号
|
||||
},
|
||||
{
|
||||
id: "654321", // 成员ID
|
||||
name: "李四", // 成员姓名
|
||||
phone: "13900000000", // 成员手机号
|
||||
}
|
||||
]); // 作业班成员列表
|
||||
const MemberArr = ref([]); // 作业班成员列表
|
||||
|
||||
|
||||
|
||||
|
|
@ -127,9 +124,90 @@ defineExpose({
|
|||
getFormData: () => formData.value,
|
||||
});
|
||||
|
||||
// 从 allData 中恢复之前填写的数据
|
||||
const restoreFormData = (data) => {
|
||||
if (!data || Object.keys(data).length === 0) return;
|
||||
|
||||
if (data.ProjectName) formData.value.ProjectName = data.ProjectName;
|
||||
if (data.Location) formData.value.Location = data.Location;
|
||||
if (data.SpecificAddress) formData.value.SpecificAddress = data.SpecificAddress;
|
||||
if (data.ResponsiblePerson) formData.value.ResponsiblePerson = data.ResponsiblePerson;
|
||||
if (data.MemberList && Array.isArray(data.MemberList)) {
|
||||
formData.value.MemberList = [...data.MemberList];
|
||||
}
|
||||
if (data.period && Array.isArray(data.period) && data.period.length >= 2) {
|
||||
if (data.period[0]) {
|
||||
startDateText.value = data.period[0];
|
||||
startDate.value = dayjs(data.period[0]).valueOf();
|
||||
}
|
||||
if (data.period[1]) {
|
||||
endDateText.value = data.period[1];
|
||||
endDate.value = dayjs(data.period[1]).valueOf();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 监听 allData.BasicsInfo 的变化,恢复表单数据
|
||||
watch(() => props.allData?.BasicsInfo, (newData) => {
|
||||
if (newData && Object.keys(newData).length > 0) {
|
||||
restoreFormData(newData);
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 获取作业班成员列表
|
||||
const fetchUserList = async () => {
|
||||
try {
|
||||
const res = await getUserList();
|
||||
console.log('获取用户列表成功:', res);
|
||||
// 接口返回的数据结构为 { total: number, rows: [...], code: 200, msg: "查询成功" }
|
||||
if (res && res.rows && Array.isArray(res.rows)) {
|
||||
// 将用户数据转换为组件需要的格式 { id: userId, name: nickName || userName }
|
||||
MemberArr.value = res.rows.map(user => ({
|
||||
id: user.userId,
|
||||
name: user.nickName || user.userName || ''
|
||||
}));
|
||||
console.log('转换后的成员列表:', MemberArr.value);
|
||||
} else if (res && res.data && Array.isArray(res.data)) {
|
||||
// 兼容其他可能的数据结构
|
||||
MemberArr.value = res.data.map(user => ({
|
||||
id: user.userId || user.id,
|
||||
name: user.nickName || user.userName || user.name || ''
|
||||
}));
|
||||
} else if (Array.isArray(res)) {
|
||||
// 兼容直接返回数组的情况
|
||||
MemberArr.value = res.map(user => ({
|
||||
id: user.userId || user.id,
|
||||
name: user.nickName || user.userName || user.name || ''
|
||||
}));
|
||||
} else {
|
||||
console.warn('用户列表数据格式不正确:', res);
|
||||
uni.showToast({
|
||||
title: '获取用户列表失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户列表失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '获取用户列表失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 生命周期钩子函数
|
||||
onMounted(() => {
|
||||
initTiandituMap();
|
||||
|
||||
// 获取作业班成员列表
|
||||
fetchUserList();
|
||||
|
||||
// 组件挂载后,从 allData 中恢复数据
|
||||
if (props.allData?.BasicsInfo && Object.keys(props.allData.BasicsInfo).length > 0) {
|
||||
restoreFormData(props.allData.BasicsInfo);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,33 +17,54 @@
|
|||
<view class="FormItem">
|
||||
<view class="FormLableBox">作业班成员</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="allData.BasicsInfo.JobClassMembers" placeholder="请输入作业班成员" readonly></u-input>
|
||||
<view class="MemberBox">
|
||||
<u-tag v-for="(member, index) in memberList" :key="member.id" shape="circle">
|
||||
{{ member.name }}
|
||||
</u-tag>
|
||||
<view v-if="!memberList || memberList.length === 0" class="empty-tip">暂无作业班成员</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox mustBox">出入证有效日期</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="formData.validTime" placeholder="请输入出入证有效日期" readonly>
|
||||
<view class="date-range-box">
|
||||
<view class="date-item">
|
||||
<u-input v-model="startValidTimeText" placeholder="开始日期" readonly>
|
||||
<template #suffix>
|
||||
<u-button text="选择日期" type="primary" size="small"
|
||||
@click="showValidTimePicker = true"></u-button>
|
||||
<u-button type="primary" size="small"
|
||||
@click="showStartValidTimePicker = true">选择日期</u-button>
|
||||
</template>
|
||||
</u-input>
|
||||
<up-datetime-picker :show="showStartValidTimePicker" v-model="startValidTime" mode="date"
|
||||
:minDate="minTimestamp" @confirm="HandleStartValidTimeConfirm"
|
||||
@cancel="showStartValidTimePicker = false" format="YYYY-MM-DD"></up-datetime-picker>
|
||||
</view>
|
||||
<view class="date-separator">至</view>
|
||||
<view class="date-item">
|
||||
<u-input v-model="endValidTimeText" placeholder="结束日期" readonly>
|
||||
<template #suffix>
|
||||
<u-button type="primary" size="small"
|
||||
@click="showEndValidTimePicker = true">选择日期</u-button>
|
||||
</template>
|
||||
</u-input>
|
||||
<up-datetime-picker :show="showEndValidTimePicker" v-model="endValidTime" mode="date"
|
||||
:minDate="endValidTimeMinTimestamp" @confirm="HandleEndValidTimeConfirm"
|
||||
@cancel="showEndValidTimePicker = false" format="YYYY-MM-DD"></up-datetime-picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<up-datetime-picker :show="showValidTimePicker" v-model="formData.validTime" mode="date"
|
||||
:minDate="minTimestamp" @confirm="HandleValidTimeConfirm" @cancel="showValidTimePicker = false"
|
||||
format="YYYY-MM-DD"></up-datetime-picker>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox FlexBox">
|
||||
<view class="mustBox">随行车辆信息</view>
|
||||
<view class="addBtn" @click="showCarPicker = true">添加</view>
|
||||
<view class="addBtn" @click="showCarInputPopup = true">添加</view>
|
||||
</view>
|
||||
<view class="FormValueBox">
|
||||
<view class="CarListBox">
|
||||
<view v-for="item in formData.CarList" :key="item.id" class="CarItem">
|
||||
<view class="CarInfoBox">
|
||||
<view class="CarTitleBox">{{ item.name }} ({{ item.code }})</view>
|
||||
<view class="CarTitleBox">{{ item.code }}</view>
|
||||
<view class="CartypeBox">{{ item.type }}</view>
|
||||
</view>
|
||||
<view>
|
||||
|
|
@ -53,8 +74,26 @@
|
|||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<u-picker :show="showCarPicker" :columns="[CarArr]" keyName="name" @confirm="HandleCarConfirm"
|
||||
@cancel="showCarPicker = false"></u-picker>
|
||||
<!-- 车辆信息输入弹窗 -->
|
||||
<u-popup :show="showCarInputPopup" mode="center" :round="10" @close="showCarInputPopup = false">
|
||||
<view class="car-input-popup">
|
||||
<view class="popup-title">添加车辆信息</view>
|
||||
<view class="popup-form">
|
||||
<view class="form-item">
|
||||
<view class="form-label">车辆类型</view>
|
||||
<u-input v-model="carInputForm.type" placeholder="请输入车辆类型" :maxlength="50"></u-input>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">车牌号</view>
|
||||
<u-input v-model="carInputForm.code" placeholder="请输入车牌号" :maxlength="20"></u-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-buttons">
|
||||
<u-button text="取消" type="info" @click="showCarInputPopup = false"></u-button>
|
||||
<u-button text="确定" type="primary" @click="HandleCarInputConfirm"></u-button>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox">附件上传</view>
|
||||
|
|
@ -70,23 +109,34 @@
|
|||
</up-upload>
|
||||
</view>
|
||||
<view class="UpFileListBox">
|
||||
<view v-for="item in fileList1" :key="item.url" class="UpFileItem">
|
||||
<view v-for="item in fileList1" :key="item.fid || item.url" class="UpFileItem">
|
||||
<view>
|
||||
<view class="UpFileName">{{ item.name }}</view>
|
||||
<view class="UpFileSize">{{ item.size }}</view>
|
||||
<view v-if="item.uploading" class="UpFileStatus">上传中...</view>
|
||||
</view>
|
||||
|
||||
<u-button text="删除" type="primary" size="small" @click="deletePic(item.fid)"></u-button>
|
||||
<u-button text="删除" type="primary" size="small" :disabled="item.uploading"
|
||||
@click="deletePic(item.fid)">
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox">备注</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="formData.remark" type="textarea" :maxlength="500" placeholder="请输入备注信息"
|
||||
:autoHeight="true"></u-input>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { generateGuid } from '@/utils/index.js';
|
||||
import dayjs from "dayjs";
|
||||
import { ref, defineExpose } from "vue";
|
||||
import { ref, computed, onMounted, watch, defineExpose } from "vue";
|
||||
import { uploadFileApi } from '@/api/modules/workTicket';
|
||||
|
||||
const props = defineProps({
|
||||
allData: {
|
||||
|
|
@ -95,36 +145,45 @@ const props = defineProps({
|
|||
}
|
||||
})
|
||||
|
||||
const showValidTimePicker = ref(false); // 出入证有效日期选择器是否显示
|
||||
const showStartValidTimePicker = ref(false); // 出入证开始有效日期选择器是否显示
|
||||
const showEndValidTimePicker = ref(false); // 出入证结束有效日期选择器是否显示
|
||||
const startValidTime = ref(null); // 开始有效日期时间戳
|
||||
const endValidTime = ref(null); // 结束有效日期时间戳
|
||||
const startValidTimeText = ref(''); // 开始有效日期显示文本
|
||||
const endValidTimeText = ref(''); // 结束有效日期显示文本
|
||||
const minTimestamp = ref(dayjs('2020-01-01').valueOf()); // 最小可选日期时间戳
|
||||
const showCarPicker = ref(false); // 随行车辆选择器是否显示
|
||||
const showCarInputPopup = ref(false); // 车辆信息输入弹窗是否显示
|
||||
|
||||
// 车辆选项列表
|
||||
const CarArr = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: '车辆1',
|
||||
type: '皮卡车',
|
||||
code: '京A123456',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '车辆2',
|
||||
type: '轿车',
|
||||
code: '京B123456',
|
||||
},
|
||||
]);
|
||||
// 结束有效日期的最小时间戳(不能小于开始日期)
|
||||
const endValidTimeMinTimestamp = computed(() => {
|
||||
if (startValidTime.value) {
|
||||
return startValidTime.value;
|
||||
}
|
||||
return minTimestamp.value;
|
||||
});
|
||||
|
||||
// 车辆信息输入表单
|
||||
const carInputForm = ref({
|
||||
type: '', // 车辆类型
|
||||
code: '', // 车牌号
|
||||
});
|
||||
|
||||
// 组件数据
|
||||
const formData = ref({
|
||||
validTime: '', // 出入证有效日期
|
||||
validTime: '', // 出入证有效日期(格式:YYYY-MM-DD 或 YYYY-MM-DD 至 YYYY-MM-DD)
|
||||
CarList: [], // 随行车辆数组
|
||||
remark: '', // 备注
|
||||
})
|
||||
|
||||
const fileList1 = ref([]); // 上传的文件列表
|
||||
|
||||
// 从基础信息中获取作业班成员列表
|
||||
const memberList = computed(() => {
|
||||
return props.allData?.BasicsInfo?.MemberList || [];
|
||||
});
|
||||
|
||||
// 处理上传文件事件
|
||||
const afterRead = (e) => {
|
||||
const afterRead = async (e) => {
|
||||
console.log('上传的文件:', e);
|
||||
let fileInfo = e.file[0];
|
||||
// 判断文件大小
|
||||
|
|
@ -144,14 +203,62 @@ const afterRead = (e) => {
|
|||
return;
|
||||
}
|
||||
|
||||
let arr = [...fileList1.value];
|
||||
arr.push({
|
||||
fid: generateGuid(),
|
||||
// 生成临时文件ID,用于标识上传中的文件
|
||||
const tempFid = generateGuid();
|
||||
const tempFile = {
|
||||
fid: tempFid,
|
||||
name: fileInfo.name,
|
||||
size: (fileInfo.size / 1024 / 1024).toFixed(2) + 'MB',
|
||||
url: fileInfo.url,
|
||||
uploading: true // 标记为上传中
|
||||
};
|
||||
|
||||
// 先添加到列表,显示上传状态
|
||||
fileList1.value.push(tempFile);
|
||||
|
||||
try {
|
||||
// 调用上传接口
|
||||
const uploadResult = await uploadFileApi(
|
||||
fileInfo.url, // 文件路径
|
||||
'file', // 文件字段名
|
||||
{}, // 额外的表单数据
|
||||
{ loading: true, loadingText: '上传中...' }
|
||||
);
|
||||
|
||||
// 上传成功,更新文件信息
|
||||
// 接口返回的数据结构: { name: "文件名", url: "文件URL" }
|
||||
const serverUrl = uploadResult?.url || fileInfo.url;
|
||||
const serverFileName = uploadResult?.name || fileInfo.name;
|
||||
// 使用服务器返回的文件名作为唯一标识,如果没有则使用临时ID
|
||||
const fileId = uploadResult?.name || tempFid;
|
||||
|
||||
// 更新文件列表中的对应项
|
||||
const fileIndex = fileList1.value.findIndex(item => item.fid === tempFid);
|
||||
if (fileIndex !== -1) {
|
||||
fileList1.value[fileIndex] = {
|
||||
fid: fileId,
|
||||
name: serverFileName, // 使用服务器返回的文件名
|
||||
size: (fileInfo.size / 1024 / 1024).toFixed(2) + 'MB',
|
||||
url: serverUrl, // 使用服务器返回的URL
|
||||
uploading: false
|
||||
};
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: '上传成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
fileList1.value = arr;
|
||||
} catch (error) {
|
||||
console.error('文件上传失败:', error);
|
||||
// 上传失败,从列表中移除
|
||||
fileList1.value = fileList1.value.filter(item => item.fid !== tempFid);
|
||||
uni.showToast({
|
||||
title: '上传失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 删除上传的文件
|
||||
|
|
@ -162,71 +269,211 @@ const deletePic = (fid) => {
|
|||
fileList1.value = arr;
|
||||
}
|
||||
|
||||
// 从 allData 中恢复之前填写的数据
|
||||
const restoreFormData = (data) => {
|
||||
if (!data || Object.keys(data).length === 0) return;
|
||||
|
||||
if (data.validTime) {
|
||||
formData.value.validTime = data.validTime;
|
||||
// 解析有效日期,恢复开始和结束日期
|
||||
const timeStr = data.validTime.trim();
|
||||
if (timeStr.includes('至')) {
|
||||
const parts = timeStr.split('至').map(s => s.trim());
|
||||
if (parts[0]) {
|
||||
startValidTimeText.value = parts[0];
|
||||
startValidTime.value = dayjs(parts[0]).valueOf();
|
||||
}
|
||||
if (parts[1]) {
|
||||
endValidTimeText.value = parts[1];
|
||||
endValidTime.value = dayjs(parts[1]).valueOf();
|
||||
}
|
||||
} else {
|
||||
startValidTimeText.value = timeStr;
|
||||
startValidTime.value = dayjs(timeStr).valueOf();
|
||||
}
|
||||
}
|
||||
if (data.CarList && Array.isArray(data.CarList)) {
|
||||
formData.value.CarList = [...data.CarList];
|
||||
}
|
||||
if (data.remark) formData.value.remark = data.remark;
|
||||
// 恢复文件列表(如果需要的话,可以从 data 中恢复)
|
||||
// if (data.fileList && Array.isArray(data.fileList)) {
|
||||
// fileList1.value = [...data.fileList];
|
||||
// }
|
||||
};
|
||||
|
||||
// 监听 allData.GatePassInfo 的变化,恢复表单数据
|
||||
watch(() => props.allData?.GatePassInfo, (newData) => {
|
||||
if (newData && Object.keys(newData).length > 0) {
|
||||
restoreFormData(newData);
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 组件暴露方法
|
||||
defineExpose({
|
||||
getFormData() {
|
||||
return formData.value;
|
||||
// 解析有效日期,支持 "YYYY-MM-DD" 或 "YYYY-MM-DD 至 YYYY-MM-DD" 格式
|
||||
let validityStartTime = '';
|
||||
let validityEndTime = '';
|
||||
|
||||
if (formData.value.validTime) {
|
||||
const timeStr = formData.value.validTime.trim();
|
||||
if (timeStr.includes('至')) {
|
||||
// 包含"至"的情况,拆分开始和结束日期
|
||||
const parts = timeStr.split('至').map(s => s.trim());
|
||||
validityStartTime = parts[0] ? `${parts[0]} 08:00:00` : '';
|
||||
validityEndTime = parts[1] ? `${parts[1]} 18:00:00` : '';
|
||||
} else {
|
||||
// 单个日期,作为开始日期,结束日期设为同一天
|
||||
validityStartTime = `${timeStr} 08:00:00`;
|
||||
validityEndTime = `${timeStr} 18:00:00`;
|
||||
}
|
||||
}
|
||||
|
||||
// 转换车辆列表格式
|
||||
const vehicleList = formData.value.CarList.map(car => ({
|
||||
licensePlate: car.code || '',
|
||||
vehicleType: car.type || ''
|
||||
}));
|
||||
|
||||
// 提取附件URL列表(只返回已上传成功的文件,排除上传中的文件)
|
||||
const attachmentList = fileList1.value
|
||||
.filter(file => !file.uploading && file.url) // 过滤掉上传中的文件和没有URL的文件
|
||||
.map(file => file.url || '')
|
||||
.filter(url => url);
|
||||
|
||||
// 从基础信息中获取项目ID和作业地点
|
||||
const projectId = props.allData?.BasicsInfo?.projectId || null;
|
||||
const workLocation = props.allData?.BasicsInfo?.SpecificAddress || '';
|
||||
|
||||
// 调试信息:打印 projectId 的值
|
||||
console.log('GatePassInfo getFormData - projectId:', projectId);
|
||||
console.log('GatePassInfo getFormData - allData.BasicsInfo:', props.allData?.BasicsInfo);
|
||||
|
||||
// 从基础信息中获取成员ID列表
|
||||
const memberList = props.allData?.BasicsInfo?.MemberList || [];
|
||||
const sysUserIds = memberList.map(member => {
|
||||
// 如果成员ID是字符串,尝试转换为数字
|
||||
const id = member.id;
|
||||
return typeof id === 'string' ? parseInt(id) || id : id;
|
||||
});
|
||||
|
||||
return {
|
||||
projectId,
|
||||
workLocation,
|
||||
sysUserIds,
|
||||
validityStartTime,
|
||||
validityEndTime,
|
||||
vehicleList,
|
||||
attachmentList,
|
||||
remark: formData.value.remark || ''
|
||||
};
|
||||
}
|
||||
})
|
||||
|
||||
// 生命周期钩子函数
|
||||
onMounted(() => {
|
||||
// 组件挂载后,从 allData 中恢复数据
|
||||
if (props.allData?.GatePassInfo && Object.keys(props.allData.GatePassInfo).length > 0) {
|
||||
restoreFormData(props.allData.GatePassInfo);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 处理出入证有效日期选择器确认事件
|
||||
const HandleValidTimeConfirm = (e) => {
|
||||
|
||||
// 处理出入证开始有效日期选择器确认事件
|
||||
const HandleStartValidTimeConfirm = (e) => {
|
||||
const selectedDate = (e.value && dayjs(e.value).isValid()) ? e.value : minTimestamp.value;
|
||||
formData.value.validTime = dayjs(selectedDate).format('YYYY-MM-DD');
|
||||
showValidTimePicker.value = false;
|
||||
startValidTimeText.value = dayjs(selectedDate).format('YYYY-MM-DD');
|
||||
startValidTime.value = selectedDate;
|
||||
endValidTimeText.value = '';
|
||||
endValidTime.value = null;
|
||||
showStartValidTimePicker.value = false;
|
||||
updateValidTime();
|
||||
}
|
||||
|
||||
// 处理车辆选择确认事件
|
||||
const HandleCarConfirm = (e) => {
|
||||
console.log('选中的车辆:', e);
|
||||
if (e.value && e.value.length > 0) {
|
||||
const selectedCar = e.value[0];
|
||||
console.log('选中的车辆:', selectedCar);
|
||||
console.log('selectedCar 的类型:', typeof selectedCar);
|
||||
// 处理出入证结束有效日期选择器确认事件
|
||||
const HandleEndValidTimeConfirm = (e) => {
|
||||
const selectedDate = (e.value && dayjs(e.value).isValid()) ? e.value : minTimestamp.value;
|
||||
|
||||
let carInfo;
|
||||
|
||||
// 判断返回的是对象还是字符串
|
||||
if (typeof selectedCar === 'object' && selectedCar !== null) {
|
||||
// 如果是对象,直接使用
|
||||
carInfo = selectedCar;
|
||||
console.log('返回的是对象,直接使用:', carInfo);
|
||||
} else {
|
||||
// 如果是字符串,从 CarArr 中根据id查找
|
||||
carInfo = CarArr.value.find(item => item.id === selectedCar);
|
||||
console.log('返回的是字符串,从 CarArr 根据id查找:', carInfo);
|
||||
}
|
||||
|
||||
if (carInfo && carInfo.id) {
|
||||
// 根据id检查车辆是否已存在
|
||||
const isExist = formData.value.CarList.some(item => item.id === carInfo.id);
|
||||
console.log('车辆是否已存在:', isExist);
|
||||
|
||||
if (!isExist) {
|
||||
formData.value.CarList.push({
|
||||
id: carInfo.id,
|
||||
name: carInfo.name,
|
||||
code: carInfo.code,
|
||||
type: carInfo.type
|
||||
});
|
||||
console.log('添加车辆成功:', carInfo);
|
||||
console.log('添加后的车辆列表:', formData.value.CarList);
|
||||
} else {
|
||||
// 检查是否选择了开始日期
|
||||
if (startValidTime.value && dayjs(selectedDate).isBefore(dayjs(startValidTime.value))) {
|
||||
uni.showToast({
|
||||
title: '该车辆已存在',
|
||||
title: '结束日期不能小于开始日期',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
endValidTimeText.value = dayjs(selectedDate).format('YYYY-MM-DD');
|
||||
endValidTime.value = selectedDate;
|
||||
showEndValidTimePicker.value = false;
|
||||
updateValidTime();
|
||||
}
|
||||
|
||||
// 更新出入证有效日期
|
||||
const updateValidTime = () => {
|
||||
if (startValidTimeText.value && endValidTimeText.value) {
|
||||
formData.value.validTime = `${startValidTimeText.value} 至 ${endValidTimeText.value}`;
|
||||
} else if (startValidTimeText.value) {
|
||||
formData.value.validTime = startValidTimeText.value;
|
||||
} else {
|
||||
console.log('未找到车辆信息或车辆信息无效');
|
||||
formData.value.validTime = '';
|
||||
}
|
||||
} else {
|
||||
console.log('e.value 为空或长度为0');
|
||||
}
|
||||
|
||||
// 处理车辆信息输入确认事件
|
||||
const HandleCarInputConfirm = () => {
|
||||
// 验证输入
|
||||
if (!carInputForm.value.type || carInputForm.value.type.trim() === '') {
|
||||
uni.showToast({
|
||||
title: '请输入车辆类型',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
showCarPicker.value = false;
|
||||
if (!carInputForm.value.code || carInputForm.value.code.trim() === '') {
|
||||
uni.showToast({
|
||||
title: '请输入车牌号',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查车牌号是否已存在
|
||||
const isExist = formData.value.CarList.some(item => item.code === carInputForm.value.code.trim());
|
||||
if (isExist) {
|
||||
uni.showToast({
|
||||
title: '该车牌号已存在',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加车辆信息
|
||||
const newCar = {
|
||||
id: generateGuid(), // 使用生成唯一ID
|
||||
type: carInputForm.value.type.trim(),
|
||||
code: carInputForm.value.code.trim()
|
||||
};
|
||||
|
||||
formData.value.CarList.push(newCar);
|
||||
console.log('添加车辆成功:', newCar);
|
||||
|
||||
// 清空表单并关闭弹窗
|
||||
carInputForm.value.type = '';
|
||||
carInputForm.value.code = '';
|
||||
showCarInputPopup.value = false;
|
||||
|
||||
uni.showToast({
|
||||
title: '添加成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
};
|
||||
|
||||
// 删除车辆
|
||||
|
|
@ -288,6 +535,12 @@ const HandleDeleteCar = (carId) => {
|
|||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.UpFileStatus {
|
||||
font-size: 24rpx;
|
||||
color: #2979ff;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -371,7 +624,81 @@ const HandleDeleteCar = (carId) => {
|
|||
.FormValueBox {
|
||||
font-size: 30rpx;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.MemberBox {
|
||||
min-height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 20rpx;
|
||||
flex-wrap: wrap;
|
||||
border: 1rpx solid #e4e7ed;
|
||||
padding: 20rpx;
|
||||
border-radius: 10rpx;
|
||||
|
||||
.empty-tip {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.date-range-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
flex: 1;
|
||||
|
||||
.date-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.date-separator {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 车辆信息输入弹窗样式
|
||||
.car-input-popup {
|
||||
width: 600rpx;
|
||||
padding: 40rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx;
|
||||
|
||||
.popup-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.popup-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 30rpx;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
|
||||
.form-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-buttons {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -4,53 +4,48 @@
|
|||
<view class="FormBox">
|
||||
<view class="H2Box">基础信息</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox FlexBox">
|
||||
<view class="mustBox">所属单位</view>
|
||||
<view class="addBtn" @click="showUnitNamePicker = true">选择</view>
|
||||
</view>
|
||||
<view class="FormLableBox mustBox">所属单位</view>
|
||||
<view class="FormValueBox">
|
||||
<view class="BorderBox">
|
||||
<view class="grayFont" v-if="!formData.unitName">请选择所属单位</view>
|
||||
<view v-else>{{ formData.unitName }}</view>
|
||||
</view>
|
||||
<u-picker v-model="formData.unitName" :columns="[unitNameList]" :show="showUnitNamePicker"
|
||||
keyName="name" @confirm="confirmUnitNamePicker" @cancel="showUnitNamePicker = false"></u-picker>
|
||||
<u-input v-model="formData.unitName" placeholder="所属单位" readonly></u-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox mustBox">票证编号</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="formData.serialNumber" placeholder="请输入票证编号" readonly></u-input>
|
||||
<u-input v-model="formData.ticketNumber" placeholder="请输入票证编号" readonly></u-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox mustBox">工作内容</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="formData.workContent" placeholder="请输入工作内容"></u-input>
|
||||
<u-input v-model="formData.workContent" placeholder="请输入工作内容" :readonly="isWorkTicketDetailLoaded"></u-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
<view class="FormLableBox FlexBox">
|
||||
<view class="mustBox">工作负责人</view>
|
||||
<view class="addBtn" @click="showWorkResponsiblePicker = true">选择</view>
|
||||
<view class="addBtn" v-if="!isWorkTicketDetailLoaded" @click="showWorkResponsiblePicker = true">选择</view>
|
||||
</view>
|
||||
<view class="FormValueBox">
|
||||
<view class="BorderBox">
|
||||
<view class="grayFont" v-if="!formData.workResponsible">请选择工作负责人</view>
|
||||
<view v-else>{{ formData.workResponsible }}</view>
|
||||
</view>
|
||||
<u-picker v-model="formData.workResponsible" :columns="[workResponsibleList]"
|
||||
<u-picker v-if="!isWorkTicketDetailLoaded" v-model="formData.workResponsible" :columns="[workResponsibleList]"
|
||||
:show="showWorkResponsiblePicker" keyName="name" @confirm="confirmWorkResponsiblePicker"
|
||||
@cancel="showWorkResponsiblePicker = false"></u-picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="H2Box">检查内容</view>
|
||||
<view class="CardBox">
|
||||
<view class="CardBoxItem" v-for="(item, index) in checkContentList" :key="item.id">
|
||||
{{ index + 1 }}: {{ item.name }}
|
||||
<view class="CardBox" v-if="checkContentList.length > 0">
|
||||
<view class="CardBoxItem" v-for="(item, index) in checkContentList" :key="item.id || index">
|
||||
第{{ index + 1 }}项: {{ item.itemDescription }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="CardBox" v-else>
|
||||
<view class="CardBoxItem grayFont">暂无检查内容</view>
|
||||
</view>
|
||||
|
||||
<view class="H2Box">附件上传</view>
|
||||
<view style="margin-top: 20rpx;">
|
||||
|
|
@ -65,13 +60,16 @@
|
|||
</up-upload>
|
||||
</view>
|
||||
<view class="UpFileListBox">
|
||||
<view v-for="item in fileList1" :key="item.url" class="UpFileItem">
|
||||
<view v-for="item in fileList1" :key="item.fid || item.url" class="UpFileItem">
|
||||
<view>
|
||||
<view class="UpFileName">{{ item.name }}</view>
|
||||
<view class="UpFileSize">{{ item.size }}</view>
|
||||
<view v-if="item.uploading" class="UpFileStatus">上传中...</view>
|
||||
</view>
|
||||
|
||||
<u-button text="删除" type="primary" size="small" @click="deletePic(item.fid)"></u-button>
|
||||
<u-button text="删除" type="primary" size="small" :disabled="item.uploading"
|
||||
@click="deletePic(item.fid)">
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -80,14 +78,21 @@
|
|||
<script setup>
|
||||
import { generateGuid } from '@/utils/index.js';
|
||||
import dayjs from 'dayjs';
|
||||
import { ref, defineExpose } from 'vue'
|
||||
import { ref, onMounted, watch, defineExpose } from 'vue'
|
||||
import { getRiskCardTemplateDetail, uploadFileApi } from '@/api/modules/workTicket'
|
||||
import { getUserInfo } from '@/api/modules/user'
|
||||
|
||||
const props = defineProps({
|
||||
allData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
templateId: {
|
||||
type: [Number, String],
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const showUnitNamePicker = ref(false); // 所属单位选择器是否显示
|
||||
const unitNameList = ref([
|
||||
{ id: 1, name: '公司11' },
|
||||
{ id: 2, name: '公司13' },
|
||||
{ id: 3, name: '公司12' },
|
||||
]);
|
||||
|
||||
// 工作负责人选择器是否显示
|
||||
const showWorkResponsiblePicker = ref(false);
|
||||
|
|
@ -98,36 +103,216 @@ const workResponsibleList = ref([
|
|||
{ id: 3, name: '王五' },
|
||||
]);
|
||||
|
||||
// 检查内容列表
|
||||
const checkContentList = ref([
|
||||
{ id: 1, name: '动火安全作业票中对应的安全风险分析是否齐全' },
|
||||
{ id: 2, name: '检查内容2' },
|
||||
{ id: 3, name: '检查内容3' },
|
||||
])
|
||||
// 检查内容列表(从模板中获取)
|
||||
const checkContentList = ref([])
|
||||
|
||||
// 模板详情数据
|
||||
const templateDetail = ref(null)
|
||||
|
||||
// 上传的文件列表
|
||||
const fileList1 = ref([]);
|
||||
|
||||
// 标记是否已加载工作票详情(用于控制字段是否可编辑)
|
||||
const isWorkTicketDetailLoaded = ref(false);
|
||||
|
||||
const formData = ref({
|
||||
serialNumber: generateGuid(), // 票证编号
|
||||
ticketNumber: generateGuid(), // 票证编号
|
||||
unitName: '', // 所属单位
|
||||
workContent: '', // 工作内容
|
||||
workResponsible: '', // 工作负责人
|
||||
})
|
||||
|
||||
// 从 allData 中恢复之前填写的数据
|
||||
const restoreFormData = (data) => {
|
||||
if (!data || Object.keys(data).length === 0) return;
|
||||
|
||||
if (data.unitName) formData.value.unitName = data.unitName;
|
||||
if (data.ticketNumber) formData.value.ticketNumber = data.ticketNumber;
|
||||
if (data.workContent) formData.value.workContent = data.workContent;
|
||||
if (data.workResponsible) formData.value.workResponsible = data.workResponsible;
|
||||
// 恢复文件列表(如果需要的话,可以从 data 中恢复)
|
||||
// if (data.fileList && Array.isArray(data.fileList)) {
|
||||
// fileList1.value = [...data.fileList];
|
||||
// }
|
||||
};
|
||||
|
||||
// 监听 allData.RiskControl 的变化,恢复表单数据
|
||||
watch(() => props.allData?.RiskControl, (newData) => {
|
||||
if (newData && Object.keys(newData).length > 0) {
|
||||
restoreFormData(newData);
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 监听工作票详情数据,自动填充票证编号、工作内容、工作负责人
|
||||
watch(() => props.allData?.RiskControl?.workTicketDetail, (workTicketDetail) => {
|
||||
if (workTicketDetail && Object.keys(workTicketDetail).length > 0) {
|
||||
console.log('工作票详情数据:', workTicketDetail);
|
||||
|
||||
// 填充票证编号
|
||||
if (workTicketDetail.ticketNumber) {
|
||||
formData.value.ticketNumber = workTicketDetail.ticketNumber;
|
||||
}
|
||||
|
||||
// 填充工作内容
|
||||
if (workTicketDetail.workContent) {
|
||||
formData.value.workContent = workTicketDetail.workContent;
|
||||
}
|
||||
|
||||
// 填充工作负责人
|
||||
if (workTicketDetail.supervisorName) {
|
||||
formData.value.workResponsible = workTicketDetail.supervisorName;
|
||||
}
|
||||
|
||||
// 标记已加载工作票详情,使字段不可编辑
|
||||
isWorkTicketDetailLoaded.value = true;
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 暴露方法,获取表单数据
|
||||
defineExpose({
|
||||
getFormData() {
|
||||
return formData.value;
|
||||
return {
|
||||
...formData.value,
|
||||
// 如果需要保存文件列表,可以在这里添加
|
||||
// fileList: fileList1.value
|
||||
};
|
||||
},
|
||||
// 获取提交数据,用于提交监理审核
|
||||
getSubmitData() {
|
||||
// 构建检查项列表
|
||||
const checkItems = checkContentList.value.map((item, index) => ({
|
||||
templateItemId: item.id || item.templateItemId || (index + 1),
|
||||
itemDescription: item.itemDescription || item.description || '',
|
||||
checkResult: item.checkResult || '合格', // 默认检查结果为"合格"
|
||||
sortOrder: item.sortOrder || (index + 1)
|
||||
}));
|
||||
|
||||
// 构建附件列表(提取已上传文件的URL)
|
||||
const attachmentList = fileList1.value
|
||||
.filter(file => !file.uploading && file.url)
|
||||
.map(file => file.url);
|
||||
|
||||
// 获取工作票详情中的信息(可能存储在多个位置)
|
||||
const workTicketDetail = props.allData?.RiskControl?.workTicketDetail
|
||||
|| props.allData?.workTicketDetail
|
||||
|| {};
|
||||
|
||||
// 格式化检查时间(使用当前时间,格式:yyyy-MM-ddTHH:mm)
|
||||
const inspectionTime = dayjs().format('YYYY-MM-DDTHH:mm');
|
||||
|
||||
return {
|
||||
ticketId: props.allData?.workTicketId || null,
|
||||
templateId: props.templateId || null,
|
||||
ticketNumber: formData.value.ticketNumber || '',
|
||||
operatingUnit: formData.value.unitName || '',
|
||||
workContent: formData.value.workContent || '',
|
||||
supervisorName: formData.value.workResponsible || workTicketDetail.supervisorName || '',
|
||||
supervisorPosition: workTicketDetail.supervisorPosition || '',
|
||||
contactMethod: workTicketDetail.contactMethod || workTicketDetail.contactPhone || '',
|
||||
inspectionTime: inspectionTime,
|
||||
checkItems: checkItems,
|
||||
attachmentList: attachmentList
|
||||
};
|
||||
}
|
||||
})
|
||||
|
||||
// 确认选择所属单位
|
||||
const confirmUnitNamePicker = (e) => {
|
||||
formData.value.unitName = e.value[0].name ? e.value[0].name : unitNameList.value[0].name;
|
||||
showUnitNamePicker.value = false;
|
||||
// 加载风险管控卡模板详情
|
||||
const loadTemplateDetail = async (templateId) => {
|
||||
if (!templateId) {
|
||||
console.warn('模板ID为空,无法加载模板详情');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await getRiskCardTemplateDetail(templateId);
|
||||
templateDetail.value = res;
|
||||
console.log('风险管控卡模板详情:', res);
|
||||
|
||||
// 根据模板详情更新检查内容列表
|
||||
// 假设模板详情中包含检查项列表,字段可能是 checkItems、items、contentList 等
|
||||
if (res) {
|
||||
if (Array.isArray(res.checkItems)) {
|
||||
checkContentList.value = res.checkItems;
|
||||
} else if (Array.isArray(res.items)) {
|
||||
checkContentList.value = res.items;
|
||||
} else if (Array.isArray(res.contentList)) {
|
||||
checkContentList.value = res.contentList;
|
||||
} else if (Array.isArray(res.list)) {
|
||||
checkContentList.value = res.list;
|
||||
} else if (res.templateContent) {
|
||||
// 如果模板内容是字符串,可以解析或直接显示
|
||||
// 这里假设需要解析为列表
|
||||
try {
|
||||
const parsed = typeof res.templateContent === 'string'
|
||||
? JSON.parse(res.templateContent)
|
||||
: res.templateContent;
|
||||
if (Array.isArray(parsed)) {
|
||||
checkContentList.value = parsed;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('模板内容解析失败:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果模板中有其他字段需要填充到表单中,可以在这里处理
|
||||
if (res.workContent && !formData.value.workContent) {
|
||||
formData.value.workContent = res.workContent;
|
||||
}
|
||||
if (res.templateName && !formData.value.templateName) {
|
||||
formData.value.templateName = res.templateName;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载风险管控卡模板详情失败:', error);
|
||||
uni.showToast({
|
||||
title: '加载模板详情失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 监听 templateId 变化
|
||||
watch(() => props.templateId, (newTemplateId) => {
|
||||
if (newTemplateId) {
|
||||
loadTemplateDetail(newTemplateId);
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
// 获取用户信息
|
||||
const loadUserInfo = async () => {
|
||||
try {
|
||||
const res = await getUserInfo();
|
||||
console.log('用户信息:', res);
|
||||
// 从响应数据中获取 deptName 作为所属单位
|
||||
if (res && res.user && res.user.dept && res.user.dept.deptName) {
|
||||
formData.value.unitName = res.user.dept.deptName;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
uni.showToast({
|
||||
title: '获取用户信息失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 生命周期钩子函数
|
||||
onMounted(() => {
|
||||
// 组件挂载后,从 allData 中恢复数据
|
||||
if (props.allData?.RiskControl && Object.keys(props.allData.RiskControl).length > 0) {
|
||||
restoreFormData(props.allData.RiskControl);
|
||||
}
|
||||
|
||||
// 如果有模板ID,加载模板详情
|
||||
if (props.templateId) {
|
||||
loadTemplateDetail(props.templateId);
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
loadUserInfo();
|
||||
});
|
||||
|
||||
|
||||
// 确认选择工作负责人
|
||||
const confirmWorkResponsiblePicker = (e) => {
|
||||
formData.value.workResponsible = e.value[0].name ? e.value[0].name : workResponsibleList.value[0].name;
|
||||
|
|
@ -135,7 +320,7 @@ const confirmWorkResponsiblePicker = (e) => {
|
|||
}
|
||||
|
||||
// 处理上传文件事件
|
||||
const afterRead = (e) => {
|
||||
const afterRead = async (e) => {
|
||||
console.log('上传的文件:', e);
|
||||
let fileInfo = e.file[0];
|
||||
// 判断文件大小
|
||||
|
|
@ -155,14 +340,62 @@ const afterRead = (e) => {
|
|||
return;
|
||||
}
|
||||
|
||||
let arr = [...fileList1.value];
|
||||
arr.push({
|
||||
fid: generateGuid(),
|
||||
// 生成临时文件ID,用于标识上传中的文件
|
||||
const tempFid = generateGuid();
|
||||
const tempFile = {
|
||||
fid: tempFid,
|
||||
name: fileInfo.name,
|
||||
size: (fileInfo.size / 1024 / 1024).toFixed(2) + 'MB',
|
||||
url: fileInfo.url,
|
||||
uploading: true // 标记为上传中
|
||||
};
|
||||
|
||||
// 先添加到列表,显示上传状态
|
||||
fileList1.value.push(tempFile);
|
||||
|
||||
try {
|
||||
// 调用上传接口
|
||||
const uploadResult = await uploadFileApi(
|
||||
fileInfo.url, // 文件路径
|
||||
'file', // 文件字段名
|
||||
{}, // 额外的表单数据
|
||||
{ loading: true, loadingText: '上传中...' }
|
||||
);
|
||||
|
||||
// 上传成功,更新文件信息
|
||||
// 接口返回的数据结构: { name: "文件名", url: "文件URL" }
|
||||
const serverUrl = uploadResult?.url || fileInfo.url;
|
||||
const serverFileName = uploadResult?.name || fileInfo.name;
|
||||
// 使用服务器返回的文件名作为唯一标识,如果没有则使用临时ID
|
||||
const fileId = uploadResult?.name || tempFid;
|
||||
|
||||
// 更新文件列表中的对应项
|
||||
const fileIndex = fileList1.value.findIndex(item => item.fid === tempFid);
|
||||
if (fileIndex !== -1) {
|
||||
fileList1.value[fileIndex] = {
|
||||
fid: fileId,
|
||||
name: serverFileName, // 使用服务器返回的文件名
|
||||
size: (fileInfo.size / 1024 / 1024).toFixed(2) + 'MB',
|
||||
url: serverUrl, // 使用服务器返回的URL
|
||||
uploading: false
|
||||
};
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: '上传成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
fileList1.value = arr;
|
||||
} catch (error) {
|
||||
console.error('文件上传失败:', error);
|
||||
// 上传失败,从列表中移除
|
||||
fileList1.value = fileList1.value.filter(item => item.fid !== tempFid);
|
||||
uni.showToast({
|
||||
title: '上传失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 删除上传的文件
|
||||
|
|
@ -311,6 +544,12 @@ const deletePic = (fid) => {
|
|||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.UpFileStatus {
|
||||
font-size: 24rpx;
|
||||
color: #2979ff;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
<view class="FormItem">
|
||||
<view class="FormLableBox mustBox">票证编号</view>
|
||||
<view class="FormValueBox">
|
||||
<u-input v-model="formData.serialNumber" placeholder="请输入票证编号" readonly></u-input>
|
||||
<u-input v-model="formData.ticketNumber" placeholder="请输入票证编号" readonly></u-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem">
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
</view>
|
||||
</view>
|
||||
<view class="FlexBox">
|
||||
<u-checkbox v-model="checkedList" label="已经确认特种作业资格"></u-checkbox>
|
||||
<u-checkbox v-model="item.checked" label="已经确认特种作业资格"></u-checkbox>
|
||||
|
||||
</view>
|
||||
|
||||
|
|
@ -119,10 +119,24 @@
|
|||
</view>
|
||||
</view>
|
||||
|
||||
<view class="H2Box">高风险作业专项</view>
|
||||
<view class="FormItem">
|
||||
<view class="H2Box" v-if="isHighRiskType">高风险作业专项</view>
|
||||
<view class="FormItem" v-if="isHighRiskType">
|
||||
<view class="FormLableBox FlexBox">
|
||||
<view >是否需要申领移动球机</view>
|
||||
<view class="mustBox">风险管控卡模板</view>
|
||||
<view class="addBtn" @click="showTemplatePicker = true">选择</view>
|
||||
</view>
|
||||
<view class="FormValueBox">
|
||||
<view class="BorderBox">
|
||||
<view class="grayFont" v-if="!selectedTemplate">请选择风险管控卡模板</view>
|
||||
<view v-else>{{ getTemplateDisplayName(selectedTemplate) }}</view>
|
||||
</view>
|
||||
<u-picker v-model="selectedTemplate" :columns="[riskCardTemplateList]" :show="showTemplatePicker"
|
||||
keyName="name" @confirm="confirmTemplatePicker" @cancel="showTemplatePicker = false"></u-picker>
|
||||
</view>
|
||||
</view>
|
||||
<view class="FormItem" v-if="isHighRiskType">
|
||||
<view class="FormLableBox FlexBox">
|
||||
<view class="mustBox">是否需要申领移动球机</view>
|
||||
<view class="FlexBox">
|
||||
<span>否</span>
|
||||
<up-switch v-model="needApplyBallMachine" @change="change"></up-switch>
|
||||
|
|
@ -141,7 +155,8 @@
|
|||
<script setup>
|
||||
import { generateGuid } from '@/utils/index.js';
|
||||
import dayjs from 'dayjs';
|
||||
import { ref, defineExpose } from 'vue'
|
||||
import { ref, onMounted, watch, defineExpose, computed, nextTick } from 'vue'
|
||||
import { getRiskCardTemplateList } from '@/api/modules/workTicket'
|
||||
|
||||
// 定义props
|
||||
const props = defineProps({
|
||||
|
|
@ -201,32 +216,160 @@ const showMeasureBox = ref(false); // 是否显示自定义安全措施输入框
|
|||
const customSafeMeasure = ref(''); // 自定义安全措施输入框值
|
||||
|
||||
// 作业班成员资质确认
|
||||
const memberList = ref([
|
||||
const memberList = ref([])
|
||||
|
||||
// 从基础信息中更新成员列表
|
||||
const updateMemberListFromBasicsInfo = (preserveCheckedState = true) => {
|
||||
const basicsInfo = props.allData?.BasicsInfo;
|
||||
if (basicsInfo && basicsInfo.MemberList && Array.isArray(basicsInfo.MemberList) && basicsInfo.MemberList.length > 0) {
|
||||
// 从基础信息中获取成员列表,并初始化勾选状态
|
||||
const savedCheckedList = props.allData?.WorkNote?.memberCheckedList || [];
|
||||
|
||||
// 如果 preserveCheckedState 为 true,且当前 memberList 已有数据,则保留现有的勾选状态
|
||||
const existingCheckedMap = new Map();
|
||||
if (preserveCheckedState && memberList.value.length > 0) {
|
||||
memberList.value.forEach(member => {
|
||||
existingCheckedMap.set(member.id, member.checked);
|
||||
});
|
||||
}
|
||||
|
||||
memberList.value = basicsInfo.MemberList.map(member => {
|
||||
// 优先使用已保存的勾选状态
|
||||
let checked = false;
|
||||
|
||||
// 首先尝试从保存的数据中恢复(优先使用保存的数据)
|
||||
const savedMember = savedCheckedList.find(m =>
|
||||
(m.id == member.id) || (m.memberId == member.id)
|
||||
);
|
||||
if (savedMember !== undefined) {
|
||||
// 如果保存的数据中明确指定了 checked 值,使用该值;否则默认为 true(已勾选)
|
||||
checked = savedMember.checked === true || savedMember.checked === 'true' || savedMember.checked === 1;
|
||||
} else if (preserveCheckedState && existingCheckedMap.has(member.id)) {
|
||||
// 如果保存的数据中没有,且需要保留状态,则使用现有的勾选状态
|
||||
checked = existingCheckedMap.get(member.id);
|
||||
}
|
||||
|
||||
return {
|
||||
id: member.id,
|
||||
name: member.name,
|
||||
status: member.status || '持证', // 默认持证,如果没有状态信息
|
||||
checked: checked
|
||||
};
|
||||
});
|
||||
} else if (props.allData?.WorkNote?.memberCheckedList && Array.isArray(props.allData.WorkNote.memberCheckedList) && props.allData.WorkNote.memberCheckedList.length > 0) {
|
||||
// 如果未回填基础信息(例如:从详情页直接带 workTicketId 跳到填写工作票),
|
||||
// 则使用工作票详情映射后的 memberCheckedList(来源:qualificationList)来渲染成员资质列表
|
||||
const savedCheckedList = props.allData.WorkNote.memberCheckedList || []
|
||||
|
||||
// 保留现有勾选状态(优先级:现有 memberList > savedCheckedList)
|
||||
const existingCheckedMap = new Map();
|
||||
if (preserveCheckedState && memberList.value.length > 0) {
|
||||
memberList.value.forEach(member => {
|
||||
existingCheckedMap.set(member.id, member.checked);
|
||||
});
|
||||
}
|
||||
|
||||
memberList.value = savedCheckedList.map((m) => {
|
||||
const id = m.id || m.memberId || m.userId
|
||||
const name = m.name || m.memberName || m.userName
|
||||
|
||||
let checked = false
|
||||
if (m.checked !== undefined) {
|
||||
checked = m.checked === true || m.checked === 'true' || m.checked === 1
|
||||
} else if (preserveCheckedState && existingCheckedMap.has(id)) {
|
||||
checked = existingCheckedMap.get(id)
|
||||
} else {
|
||||
// 没提供时,默认按“已确认”展示更符合“详情回填”预期
|
||||
checked = true
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
status: m.status || '持证',
|
||||
checked
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 如果没有基础信息,使用默认的测试数据(仅用于开发测试)
|
||||
// 保留现有的勾选状态
|
||||
const existingCheckedMap = new Map();
|
||||
if (preserveCheckedState && memberList.value.length > 0) {
|
||||
memberList.value.forEach(member => {
|
||||
existingCheckedMap.set(member.id, member.checked);
|
||||
});
|
||||
}
|
||||
|
||||
// 从保存的数据中恢复勾选状态
|
||||
const savedCheckedList = props.allData?.WorkNote?.memberCheckedList || [];
|
||||
|
||||
memberList.value = [
|
||||
{
|
||||
id: 1,
|
||||
name: '张三',
|
||||
status: '持证',
|
||||
checked: (() => {
|
||||
const saved = savedCheckedList.find(m => (m.id == 1) || (m.memberId == 1));
|
||||
if (saved !== undefined) {
|
||||
return saved.checked === true || saved.checked === 'true' || saved.checked === 1;
|
||||
}
|
||||
return preserveCheckedState && existingCheckedMap.has(1) ? existingCheckedMap.get(1) : false;
|
||||
})(),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '李四',
|
||||
status: '未持证',
|
||||
checked: (() => {
|
||||
const saved = savedCheckedList.find(m => (m.id == 2) || (m.memberId == 2));
|
||||
if (saved !== undefined) {
|
||||
return saved.checked === true || saved.checked === 'true' || saved.checked === 1;
|
||||
}
|
||||
return preserveCheckedState && existingCheckedMap.has(2) ? existingCheckedMap.get(2) : false;
|
||||
})(),
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '王五',
|
||||
status: '持证',
|
||||
checked: (() => {
|
||||
const saved = savedCheckedList.find(m => (m.id == 3) || (m.memberId == 3));
|
||||
if (saved !== undefined) {
|
||||
return saved.checked === true || saved.checked === 'true' || saved.checked === 1;
|
||||
}
|
||||
return preserveCheckedState && existingCheckedMap.has(3) ? existingCheckedMap.get(3) : false;
|
||||
})(),
|
||||
},
|
||||
])
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 是否需要申领移动球机
|
||||
const needApplyBallMachine = ref(false);
|
||||
|
||||
// 判断是否为高等风险类型
|
||||
const isHighRiskType = computed(() => {
|
||||
return formData.value.riskType && formData.value.riskType.includes('高等风险');
|
||||
});
|
||||
|
||||
// 风险管控卡模板相关
|
||||
const showTemplatePicker = ref(false); // 是否显示模板选择器
|
||||
const riskCardTemplateList = ref([]); // 风险管控卡模板列表
|
||||
const selectedTemplate = ref(null); // 选中的模板
|
||||
const selectedTemplateId = ref(null); // 选中的模板ID
|
||||
|
||||
// 安全措施复选框的值
|
||||
const checkboxValue1 = ref([]);
|
||||
// 复选框变化事件
|
||||
const checkboxChange = (e) => {
|
||||
console.log('安全措施选择变化:', e);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 组件数据
|
||||
const formData = ref({
|
||||
serialNumber: '', // 票证编号
|
||||
ticketNumber: '', // 票证编号
|
||||
projectName: '', // 所属项目
|
||||
workLocation: '', // 作业地点
|
||||
workResponsible: '', // 作业负责人
|
||||
|
|
@ -245,13 +388,181 @@ const endDateText = ref(''); // 结束日期显示文本
|
|||
const minTimestamp = ref(dayjs('2020-01-01').valueOf()); // 最小可选日期时间戳
|
||||
|
||||
|
||||
// 从 allData 中恢复之前填写的数据
|
||||
const restoreFormData = (data) => {
|
||||
if (!data || Object.keys(data).length === 0) return;
|
||||
|
||||
if (data.ticketNumber) formData.value.ticketNumber = data.ticketNumber;
|
||||
if (data.projectName) formData.value.projectName = data.projectName;
|
||||
if (data.workLocation) formData.value.workLocation = data.workLocation;
|
||||
if (data.workResponsible) formData.value.workResponsible = data.workResponsible;
|
||||
if (data.workContent) formData.value.workContent = data.workContent;
|
||||
if (data.riskType) formData.value.riskType = data.riskType;
|
||||
if (data.period && Array.isArray(data.period) && data.period.length >= 2) {
|
||||
if (data.period[0]) {
|
||||
startDateText.value = data.period[0];
|
||||
startDate.value = dayjs(data.period[0]).valueOf();
|
||||
}
|
||||
if (data.period[1]) {
|
||||
endDateText.value = data.period[1];
|
||||
endDate.value = dayjs(data.period[1]).valueOf();
|
||||
}
|
||||
}
|
||||
// 恢复其他数据字段
|
||||
if (data.safeMeasures && Array.isArray(data.safeMeasures)) {
|
||||
checkboxValue1.value = [...data.safeMeasures];
|
||||
}
|
||||
if (data.needApplyBallMachine !== undefined) {
|
||||
needApplyBallMachine.value = data.needApplyBallMachine;
|
||||
}
|
||||
// 恢复作业班成员资质确认状态
|
||||
// 注意:成员列表可能还没有从基础信息中加载,所以先更新成员列表,再恢复勾选状态
|
||||
// 先更新成员列表,updateMemberListFromBasicsInfo 函数会从 allData.WorkNote.memberCheckedList 中恢复勾选状态
|
||||
updateMemberListFromBasicsInfo(true);
|
||||
// 如果 data.memberCheckedList 存在,再次确保勾选状态正确恢复(双重保险)
|
||||
if (data.memberCheckedList && Array.isArray(data.memberCheckedList) && data.memberCheckedList.length > 0) {
|
||||
// 根据成员ID恢复勾选状态
|
||||
data.memberCheckedList.forEach(checkedMember => {
|
||||
const member = memberList.value.find(m =>
|
||||
(m.id == checkedMember.id) || (m.id == checkedMember.memberId)
|
||||
);
|
||||
if (member) {
|
||||
// 确保正确恢复勾选状态:如果保存的数据中 checked 为 true,则设置为 true
|
||||
member.checked = checkedMember.checked === true || checkedMember.checked === 'true' || checkedMember.checked === 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
// 恢复风险管控卡模板
|
||||
if (data.riskCardTemplateId) {
|
||||
selectedTemplateId.value = data.riskCardTemplateId;
|
||||
// 如果模板列表已加载,尝试找到对应的模板对象
|
||||
if (riskCardTemplateList.value.length > 0) {
|
||||
restoreSelectedTemplate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 恢复选中的风险管控卡模板
|
||||
const restoreSelectedTemplate = () => {
|
||||
if (selectedTemplateId.value && riskCardTemplateList.value.length > 0) {
|
||||
const template = riskCardTemplateList.value.find(t =>
|
||||
(t.id || t.templateId || t.template_id) == selectedTemplateId.value
|
||||
);
|
||||
if (template) {
|
||||
selectedTemplate.value = template;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 监听 allData.WorkNote 的变化,恢复表单数据
|
||||
watch(() => props.allData?.WorkNote, (newData) => {
|
||||
if (newData && Object.keys(newData).length > 0) {
|
||||
restoreFormData(newData);
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 暴露的组件方法
|
||||
defineExpose({
|
||||
getFormData() {
|
||||
return formData.value;
|
||||
// 构建成员勾选状态列表
|
||||
const memberCheckedList = memberList.value.map(member => ({
|
||||
id: member.id,
|
||||
name: member.name,
|
||||
checked: member.checked || false
|
||||
}));
|
||||
|
||||
return {
|
||||
...formData.value,
|
||||
period: formData.value.period || [startDateText.value, endDateText.value],
|
||||
safeMeasures: checkboxValue1.value,
|
||||
needApplyBallMachine: needApplyBallMachine.value,
|
||||
riskCardTemplateId: selectedTemplateId.value, // 风险管控卡模板ID
|
||||
memberCheckedList: memberCheckedList // 作业班成员资质确认状态
|
||||
};
|
||||
}
|
||||
})
|
||||
|
||||
// 从基础信息中获取项目信息
|
||||
const initFromBasicsInfo = () => {
|
||||
const basicsInfo = props.allData?.BasicsInfo;
|
||||
if (basicsInfo) {
|
||||
if (basicsInfo.ProjectName && !formData.value.projectName) {
|
||||
formData.value.projectName = basicsInfo.ProjectName;
|
||||
}
|
||||
if (basicsInfo.SpecificAddress && !formData.value.workLocation) {
|
||||
formData.value.workLocation = basicsInfo.SpecificAddress;
|
||||
}
|
||||
if (basicsInfo.ResponsiblePerson && !formData.value.workResponsible) {
|
||||
formData.value.workResponsible = basicsInfo.ResponsiblePerson;
|
||||
}
|
||||
// 更新成员列表,保留现有的勾选状态
|
||||
updateMemberListFromBasicsInfo(true);
|
||||
}
|
||||
};
|
||||
|
||||
// 监听基础信息变化
|
||||
watch(() => props.allData?.BasicsInfo, (newData) => {
|
||||
if (newData && Object.keys(newData).length > 0) {
|
||||
initFromBasicsInfo();
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 生成票证编号
|
||||
const generateticketNumber = () => {
|
||||
// 如果已经有编号了,不重新生成
|
||||
if (formData.value.ticketNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前年月(YYYYMM格式)
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||
const yearMonth = `${year}${month}`;
|
||||
|
||||
// 生成4位随机序号(0001-9999)
|
||||
const randomNum = Math.floor(Math.random() * 9999) + 1;
|
||||
const serialNum = String(randomNum).padStart(4, '0');
|
||||
|
||||
// 组合成完整编号:HQ-GZP-YYYYMM-XXXX
|
||||
formData.value.ticketNumber = `HQ-GZP-${yearMonth}-${serialNum}`;
|
||||
};
|
||||
|
||||
// 生命周期钩子函数
|
||||
onMounted(() => {
|
||||
// 从基础信息中初始化(这会更新成员列表,但会从保存的数据中恢复勾选状态)
|
||||
initFromBasicsInfo();
|
||||
|
||||
// 组件挂载后,从 allData 中恢复数据(这会确保所有数据都被正确恢复,包括勾选状态)
|
||||
if (props.allData?.WorkNote && Object.keys(props.allData.WorkNote).length > 0) {
|
||||
restoreFormData(props.allData.WorkNote);
|
||||
}
|
||||
|
||||
// 如果没有编号,自动生成
|
||||
if (!formData.value.ticketNumber) {
|
||||
generateticketNumber();
|
||||
}
|
||||
|
||||
// 确保成员列表已初始化(如果还没有初始化)
|
||||
if (memberList.value.length === 0) {
|
||||
updateMemberListFromBasicsInfo(true);
|
||||
}
|
||||
|
||||
// 最后再次确保勾选状态正确恢复(使用 nextTick 确保在 DOM 更新后执行)
|
||||
nextTick(() => {
|
||||
if (props.allData?.WorkNote?.memberCheckedList && Array.isArray(props.allData.WorkNote.memberCheckedList)) {
|
||||
props.allData.WorkNote.memberCheckedList.forEach(checkedMember => {
|
||||
const member = memberList.value.find(m =>
|
||||
(m.id == checkedMember.id) || (m.id == checkedMember.memberId)
|
||||
);
|
||||
if (member) {
|
||||
member.checked = checkedMember.checked === true || checkedMember.checked === 'true' || checkedMember.checked === 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 确认选择风险类型
|
||||
const confirmRiskTypePicker = (e) => {
|
||||
formData.value.riskType = e.value[0].name;
|
||||
|
|
@ -322,6 +633,91 @@ const addCustomSafeMeasure = () => {
|
|||
}
|
||||
}
|
||||
|
||||
// 处理移动球机开关变化
|
||||
const change = (e) => {
|
||||
console.log('移动球机开关状态变化:', e);
|
||||
}
|
||||
|
||||
// 加载风险管控卡模板列表
|
||||
const loadRiskCardTemplateList = async () => {
|
||||
try {
|
||||
const res = await getRiskCardTemplateList({status: '1'});
|
||||
// 处理返回的数据,可能是数组或对象
|
||||
let templateList = [];
|
||||
if (Array.isArray(res)) {
|
||||
templateList = res;
|
||||
} else if (res && Array.isArray(res.list)) {
|
||||
templateList = res.list;
|
||||
} else if (res && Array.isArray(res.rows)) {
|
||||
templateList = res.rows;
|
||||
} else if (res && Array.isArray(res.data)) {
|
||||
templateList = res.data;
|
||||
}
|
||||
|
||||
// 统一处理模板数据,确保每个模板都有 name 字段用于显示
|
||||
riskCardTemplateList.value = templateList.map(template => ({
|
||||
...template,
|
||||
name: template.templateName || template.name || template.title || `模板${template.id || template.templateId || ''}`
|
||||
}));
|
||||
|
||||
console.log('风险管控卡模板列表:', riskCardTemplateList.value);
|
||||
|
||||
// 模板列表加载完成后,恢复选中的模板
|
||||
restoreSelectedTemplate();
|
||||
} catch (error) {
|
||||
console.error('加载风险管控卡模板列表失败:', error);
|
||||
uni.showToast({
|
||||
title: '加载模板列表失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 获取模板显示名称
|
||||
const getTemplateDisplayName = (template) => {
|
||||
if (!template) return '';
|
||||
return template.templateName || template.name || template.title || `模板${template.id || template.templateId || ''}`;
|
||||
}
|
||||
|
||||
// 确认选择风险管控卡模板
|
||||
const confirmTemplatePicker = (e) => {
|
||||
if (e.value && e.value.length > 0) {
|
||||
const template = e.value[0];
|
||||
selectedTemplate.value = template;
|
||||
// 支持多种可能的ID字段名
|
||||
selectedTemplateId.value = template.id || template.templateId || template.template_id;
|
||||
console.log('选中的模板:', template, '模板ID:', selectedTemplateId.value);
|
||||
}
|
||||
showTemplatePicker.value = false;
|
||||
}
|
||||
|
||||
// 监听风险类型变化,如果是高风险类型则加载模板列表
|
||||
watch(() => formData.value.riskType, (newRiskType) => {
|
||||
if (newRiskType && newRiskType.includes('高等风险')) {
|
||||
// 如果是高风险类型,加载模板列表
|
||||
if (riskCardTemplateList.value.length === 0) {
|
||||
loadRiskCardTemplateList().then(() => {
|
||||
// 模板列表加载完成后,恢复选中的模板
|
||||
restoreSelectedTemplate();
|
||||
});
|
||||
} else {
|
||||
// 如果模板列表已存在,直接恢复选中的模板
|
||||
restoreSelectedTemplate();
|
||||
}
|
||||
} else {
|
||||
// 如果不是高风险类型,清空选中的模板
|
||||
selectedTemplate.value = null;
|
||||
selectedTemplateId.value = null;
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
// 监听模板列表变化,当列表加载完成后恢复选中的模板
|
||||
watch(() => riskCardTemplateList.value, (newList) => {
|
||||
if (newList.length > 0 && selectedTemplateId.value) {
|
||||
restoreSelectedTemplate();
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.BlueTxt {
|
||||
|
|
@ -342,6 +738,11 @@ const addCustomSafeMeasure = () => {
|
|||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.grayFont {
|
||||
font-size: 28rpx;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.FlexBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { login } from '@/api'
|
||||
import { useUserStore } from '@/store/user'
|
||||
|
||||
const formData = reactive({
|
||||
username: '',
|
||||
|
|
@ -48,15 +50,56 @@ const roleList = ref([
|
|||
])
|
||||
|
||||
const loading = ref(false)
|
||||
const userStore = useUserStore()
|
||||
|
||||
async function handleLogin() {
|
||||
// 表单验证
|
||||
if (!formData.username) {
|
||||
uni.showToast({ title: '请输入账号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!formData.password) {
|
||||
uni.showToast({ title: '请输入密码', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!formData.role) {
|
||||
uni.showToast({ title: '请选择角色', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
// 登录逻辑
|
||||
// 调用登录接口
|
||||
const response = await login({
|
||||
username: formData.username,
|
||||
password: formData.password,
|
||||
role: formData.role
|
||||
})
|
||||
console.log(response);
|
||||
|
||||
// 保存用户信息和token
|
||||
if (response) {
|
||||
userStore.setUserInfo(response)
|
||||
if (response.access_token) {
|
||||
userStore.setToken(response.access_token)
|
||||
}
|
||||
if (response.refreshToken) {
|
||||
userStore.setRefreshToken(response.refreshToken)
|
||||
}
|
||||
}
|
||||
|
||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||
|
||||
// 跳转到工作台页面
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/WorkOrderApproval/index' })
|
||||
}, 1500)
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
uni.showToast({
|
||||
title: error?.message || '登录失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,5 +22,17 @@ export default defineConfig({
|
|||
},
|
||||
optimizeDeps: {
|
||||
include: ['uview-plus']
|
||||
},
|
||||
// H5 开发环境代理配置,解决跨域问题
|
||||
server: {
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://172.16.1.146:8080',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
secure: false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue