代码提交

This commit is contained in:
lixiaobang 2026-01-29 10:37:28 +08:00
parent 005ce674db
commit 476b9f79cb
15 changed files with 4069 additions and 313 deletions

View File

@ -1,2 +1,3 @@
export * from './auth'
export * from './user'
export * from './modules/auth'
export * from './modules/user'
export * from './modules/workTicket'

View File

@ -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')
}

View File

@ -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可以是单个IDID数组或逗号分隔的字符串
* @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} 返回风险管控卡IDcardId
*/
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}`)
}

View File

@ -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

View File

@ -43,7 +43,13 @@
"minified": true,
"postcss": true
},
"usingComponents": true
"usingComponents": true,
"requiredPrivateInfos": [],
"permission": {
"scope.userLocation": {
"desc": "您的位置信息将用于小程序位置接口的效果展示"
}
}
},
"mp-alipay": {
"usingComponents": true

View File

@ -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稿1234
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

View File

@ -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 {

View File

@ -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);
}
});

View File

@ -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>

View File

@ -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);
//
// checkItemsitemscontentList
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>

View File

@ -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
// 使 memberCheckedListqualificationList
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}`;
// 40001-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

View File

@ -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
}

View File

@ -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
}
}
}
})