代码修改

This commit is contained in:
qiuyuan 2025-11-05 09:37:21 +08:00
parent 87e954ea40
commit 5ef60880b6
3 changed files with 275 additions and 188 deletions

View File

@ -20,3 +20,6 @@ export const getBackWorkOrderList = (params) => request.basic.get(`/api/v1/order
// 工单详情 // 工单详情
export const getWorkOrderDetail = (id) => request.basic.get(`/api/v1/orders/${id}`) export const getWorkOrderDetail = (id) => request.basic.get(`/api/v1/orders/${id}`)
// 派单
export const sendWorkOrder = (id, params) => request.basic.put(`/api/v1/orders${id}`, params)

View File

@ -1,28 +1,12 @@
<!-- src/components/DispatchDrawer.vue --> <!-- src/components/DispatchDrawer.vue -->
<template> <template>
<a-drawer <a-drawer title="派单" :open="open" :width="600" @close="handleCancel" :destroy-on-close="true">
title="派单" <a-form :rules="rules" ref="formRef" layout="vertical" class="form-mode" :model="formModel">
:open="visible"
:width="600"
@close="handleClose"
:destroy-on-close="true"
>
<a-form
:model="formModel"
:rules="rules"
ref="formRef"
layout="vertical"
class="form-mode"
>
<!-- 服务对象 --> <!-- 服务对象 -->
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :xs="12"> <a-col :xs="12">
<a-form-item label="服务对象"> <a-form-item label="服务对象">
<a-input <a-input v-model:value="formModel.serviceTarget" placeholder="请输入服务对象名称" disabled />
v-model:value="formModel.serviceTarget"
placeholder="请输入服务对象名称"
disabled
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -31,11 +15,7 @@
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :xs="12"> <a-col :xs="12">
<a-form-item label="服务项目" name="serviceItem"> <a-form-item label="服务项目" name="serviceItem">
<a-select <a-select v-model:value="formModel.serviceItem" placeholder="请选择服务项目" mode="multiple">
v-model:value="formModel.serviceItem"
placeholder="请选择服务项目"
mode="multiple"
>
<a-select-option value="兴趣活动">兴趣活动</a-select-option> <a-select-option value="兴趣活动">兴趣活动</a-select-option>
<a-select-option value="居家照护">居家照护</a-select-option> <a-select-option value="居家照护">居家照护</a-select-option>
<a-select-option value="医疗护理">医疗护理</a-select-option> <a-select-option value="医疗护理">医疗护理</a-select-option>
@ -44,12 +24,8 @@
</a-col> </a-col>
<a-col :xs="12"> <a-col :xs="12">
<a-form-item label="服务费用"> <a-form-item label="服务费用">
<a-input-number <a-input-number v-model:value="formModel.serviceFee" placeholder="由关联服务项目计算得出" style="width: 100%"
v-model:value="formModel.serviceFee" :min="0" />
placeholder="由关联服务项目计算得出"
style="width: 100%"
:min="0"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -58,15 +34,8 @@
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :xs="12"> <a-col :xs="12">
<a-form-item label="服务人员" name="serviceStaff"> <a-form-item label="服务人员" name="serviceStaff">
<a-select <a-select v-model:value="formModel.serviceStaff" placeholder="请选择服务人员">
v-model:value="formModel.serviceStaff" <a-select-option v-for="user in assignees" :key="user.id" :value="user.id">
placeholder="请选择服务人员"
>
<a-select-option
v-for="user in assignees"
:key="user.id"
:value="user.id"
>
{{ user.name }} {{ user.name }}
</a-select-option> </a-select-option>
</a-select> </a-select>
@ -78,11 +47,7 @@
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :xs="24"> <a-col :xs="24">
<a-form-item label="计划日期" name="plannedDate"> <a-form-item label="计划日期" name="plannedDate">
<a-range-picker <a-range-picker v-model:value="formModel.plannedDate" style="width: 100%" :placeholder="['开始日期', '结束日期']" />
v-model:value="formModel.plannedDate"
style="width: 100%"
:placeholder="['开始日期', '结束日期']"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -91,21 +56,13 @@
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :xs="12"> <a-col :xs="12">
<a-form-item label="计划开始时间" name="plannedStartTime"> <a-form-item label="计划开始时间" name="plannedStartTime">
<a-time-picker <a-time-picker v-model:value="formModel.plannedStartTime" placeholder="请选择计划开始时间" style="width: 100%"
v-model:value="formModel.plannedStartTime" format="HH:mm" :minute-step="5" />
placeholder="请选择计划开始时间"
style="width: 100%"
format="HH:mm"
:minute-step="5"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :xs="12"> <a-col :xs="12">
<a-form-item label="要求工单时长" name="requiredDuration"> <a-form-item label="要求工单时长" name="requiredDuration">
<a-input <a-input v-model:value="formModel.requiredDuration" placeholder="请输入要求工单时长">
v-model:value="formModel.requiredDuration"
placeholder="请输入要求工单时长"
>
<template #suffix>分钟</template> <template #suffix>分钟</template>
</a-input> </a-input>
</a-form-item> </a-form-item>
@ -116,14 +73,8 @@
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :xs="24"> <a-col :xs="24">
<a-form-item label="服务地址" name="serviceArea"> <a-form-item label="服务地址" name="serviceArea">
<AreaCascader <AreaCascader v-model:value="formModel.serviceArea" style="width: 100%; margin-bottom: 8px;" />
v-model:value="formModel.serviceArea" <a-input v-model:value="formModel.detailedAddress" placeholder="详细地址" />
style="width: 100%; margin-bottom: 8px;"
/>
<a-input
v-model:value="formModel.detailedAddress"
placeholder="详细地址"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -132,10 +83,7 @@
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :xs="24"> <a-col :xs="24">
<a-form-item label="服务内容"> <a-form-item label="服务内容">
<a-input <a-input v-model:value="formModel.serviceContent" placeholder="填写服务内容充当备注作用此字段数据会在app工单中显示" />
v-model:value="formModel.serviceContent"
placeholder="填写服务内容充当备注作用此字段数据会在app工单中显示"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -143,8 +91,8 @@
<template #footer> <template #footer>
<div class="select-btn" style="display: flex; justify-content: flex-end; gap: 8px;"> <div class="select-btn" style="display: flex; justify-content: flex-end; gap: 8px;">
<a-button @click="handleClose">取消</a-button> <a-button @click="handleCancel">取消</a-button>
<a-button type="primary" @click="handleSubmit">确定</a-button> <a-button type="primary" @click="handleOk" :loading="confirmLoading">确定</a-button>
</div> </div>
</template> </template>
</a-drawer> </a-drawer>
@ -153,9 +101,13 @@
<script setup> <script setup>
import { ref, reactive, watch, nextTick } from 'vue' import { ref, reactive, watch, nextTick } from 'vue'
import AreaCascader from '@/components/AreaCascader/index.vue' import AreaCascader from '@/components/AreaCascader/index.vue'
import { message } from 'ant-design-vue'
import apis from '@/apis'
import dayjs from 'dayjs'
// props
const props = defineProps({ const props = defineProps({
visible: { open: {
type: Boolean, type: Boolean,
default: false default: false
}, },
@ -171,12 +123,17 @@ const props = defineProps({
const emit = defineEmits(['close', 'submit']) const emit = defineEmits(['close', 'submit'])
//
const formRef = ref() const formRef = ref()
const confirmLoading = ref(false)
// 使 formModel formData
const formModel = reactive({ const formModel = reactive({
serviceTarget: '', serviceTarget: '',
serviceItem: [], serviceItem: [],
serviceFee: undefined, serviceFee: undefined,
serviceStaff: undefined, serviceStaff: undefined,
serviceStaffId: undefined,
plannedDate: [], plannedDate: [],
plannedStartTime: null, plannedStartTime: null,
requiredDuration: '', requiredDuration: '',
@ -185,6 +142,7 @@ const formModel = reactive({
serviceContent: '' serviceContent: ''
}) })
//
const rules = { const rules = {
serviceItem: [{ required: true, message: '请选择服务项目', trigger: 'change' }], serviceItem: [{ required: true, message: '请选择服务项目', trigger: 'change' }],
serviceStaff: [{ required: true, message: '请选择服务人员', trigger: 'change' }], serviceStaff: [{ required: true, message: '请选择服务人员', trigger: 'change' }],
@ -195,47 +153,195 @@ const rules = {
detailedAddress: [{ required: true, message: '请输入详细地址', trigger: 'blur' }] detailedAddress: [{ required: true, message: '请输入详细地址', trigger: 'blur' }]
} }
// visible // ================== Methods ==================
/**
* 确认提交
*/
async function handleOk() {
try {
confirmLoading.value = true
await formRef.value.validate()
//
let plannedStart = null
let plannedEnd = null
if (formModel.plannedDate[0] && formModel.plannedStartTime) {
const datePart = formModel.plannedDate[0].format('YYYY-MM-DD')
const timePart = formModel.plannedStartTime.format('HH:mm')
plannedStart = dayjs(`${datePart} ${timePart}`)
plannedEnd = plannedStart.add(Number(formModel.requiredDuration) || 0, 'minute')
}
const submitData = {
customerId: props.initialValues.id,
projects: formModel.serviceItem,
price: formModel.serviceFee,
servicePerson: formModel.serviceStaff,
servicePersonId: formModel.serviceStaffId,
plannedStartDate: plannedStart?.toISOString() || null,
plannedEndDate: plannedEnd?.toISOString() || null,
plannedServiceStartDate: Number(formModel.requiredDuration) || 0,
areaLabels: formModel.serviceArea,
areaCodes: formModel.serviceArea.join(','),
detailAddress: formModel.detailedAddress,
content: formModel.serviceContent
}
console.log('提交数据:', submitData)
const { success } = await apis.workOrder.sendWorkOrder(submitData)
if (success) {
message.success('派单成功')
emit('submit', submitData)
}
} catch (error) {
console.log('表单校验或提交失败:', error)
// message.error('')
} finally {
confirmLoading.value = false
}
}
/**
* 取消/关闭弹框
*/
function handleCancel() {
resetFormModel()
emit('close')
}
/**
* 重置表单数据
*/
function resetFormModel() {
Object.keys(formModel).forEach(key => {
if (Array.isArray(formModel[key])) {
formModel[key] = []
} else if (typeof formModel[key] === 'string') {
formModel[key] = ''
} else {
formModel[key] = undefined
}
})
// 使 clearValidate resetFields
if (formRef.value?.clearValidate) {
formRef.value.clearValidate()
}
}
/**
* 设置表单字段值
*/
function setFormFields(values) {
//
for (const key in formModel) {
if (key in values) {
formModel[key] = values[key]
} else {
//
formModel[key] = Array.isArray(formModel[key]) ? [] : typeof formModel[key] === 'string' ? '' : undefined
}
}
nextTick(() => {
if (formRef.value?.clearValidate) {
formRef.value.clearValidate()
}
})
}
/**
* 加载工单详情并填充表单
* @param {string} id - 工单ID
*/
async function loadWorkOrderDetail(id) {
console.log('开始加载工单详情ID:', id)
try {
const { success, data } = await apis.workOrder.getWorkOrderDetail(id)
console.log('工单详情接口响应:', { success, data })
if (success && data) {
const detailData = data
console.log('工单详情数据:', detailData)
let projects = detailData.projects.map(item => item.name)
//
const formData = {
serviceTarget: detailData.customer.name || '',
serviceItem: projects,
serviceFee: detailData.price,
serviceStaff: detailData.servicePerson || undefined,
servicePersonId: detailData.servicePersonId,
plannedDate: detailData.plannedEndDate ? [
dayjs(detailData.plannedEndDate),
dayjs(detailData.plannedEndDate)
] : [],
// Day.js
plannedStartTime: detailData.plannedStartDate
? dayjs(detailData.plannedStartDate)
: null,
requiredDuration: detailData.plannedServiceStartDate ?
String(detailData.plannedServiceStartDate) : '',
serviceArea: (detailData.areaLabels || []).join('/'),
detailedAddress: detailData.detailAddress || '',
serviceContent: detailData.content || ''
}
console.log('构建的表单数据:', formData)
//
setFormFields(formData)
console.log('设置后的 formModel:', formModel)
} else {
message.error('获取工单详情失败')
}
} catch (error) {
console.error('获取工单详情失败:', error)
// message.error('')
}
}
/**
* 辅助函数将区域字符串转换为数组格式
* @param {string} areaString - 区域字符串
* @returns {Array} 区域数组
*/
function parseAreaToArray(areaString) {
if (!areaString) return []
return areaString.split('/') || []
}
// open
watch( watch(
() => props.visible, () => props.open,
(newVal) => { async (newVal) => {
if (newVal) { if (newVal) {
nextTick(() => { console.log('抽屉打开,重置表单')
if (Object.keys(props.initialValues).length > 0) { resetFormModel()
Object.assign(formModel, props.initialValues)
} else { // DOM
// await nextTick()
for (const key in formModel) {
if (Array.isArray(formModel[key])) { if (props.initialValues && props.initialValues.id) {
formModel[key] = [] console.log('加载工单详情ID:', props.initialValues.id)
} else if (typeof formModel[key] === 'string') { await loadWorkOrderDetail(props.initialValues.id)
formModel[key] = '' } else {
} else { console.log('新建派单,无初始值')
formModel[key] = undefined //
} setFormFields({
} serviceTarget: '新建测试数据',
formRef.value?.resetFields() serviceItem: ['兴趣活动'],
} serviceFee: 100,
}) requiredDuration: '60'
})
}
} }
} }
) )
const handleClose = () => {
formRef.value?.resetFields()
emit('close')
}
const handleSubmit = async () => {
try {
const values = await formRef.value.validateFields()
// model
emit('submit', { ...formModel })
handleClose()
} catch (error) {
console.log('校验失败:', error)
}
}
</script> </script>
<style scoped> <style scoped>

View File

@ -135,7 +135,7 @@
<a-button type="primary">导出记录</a-button> <a-button type="primary">导出记录</a-button>
</a-space> </a-space>
</div> </div>
<a-table rowKey="id" :loading="loading" :pagination="paginationConfig" :columns="columns" <a-table rowKey="id" :loading="loading" :pagination="paginationState" :columns="columns"
:data-source="listData" :scroll="{ x: totalWidth }" @change="onTableChange"> :data-source="listData" :scroll="{ x: totalWidth }" @change="onTableChange">
<template #bodyCell="{ column, record, index }"> <template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'serialNumber'"> <template v-if="column.key === 'serialNumber'">
@ -161,8 +161,12 @@
</a-row> </a-row>
<!-- 派单抽屉右侧弹出 --> <!-- 派单抽屉右侧弹出 -->
<DispatchDrawer :visible="showDrawer" :assignees="staffList" :initial-values="initialValues" <DispatchDrawer
@close="showDrawer = false" @submit="handleDispatchSubmit" /> :open="showDrawer"
:assignees="staffList"
:initial-values="drawerInitialValues"
@close="handleDrawerClose"
@submit="handleDispatchSubmit" />
</template> </template>
<script setup> <script setup>
@ -172,14 +176,18 @@ import { message } from 'ant-design-vue'
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import DispatchDrawer from './components/DispatchDrawer.vue'; import DispatchDrawer from './components/DispatchDrawer.vue';
import apis from '@/apis'
import { usePagination } from '@/hooks'
import storage from '@/utils/storage'
defineOptions({ defineOptions({
name: 'allocation', name: 'allocation',
}) })
const { t } = useI18n() const { t } = useI18n()
const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination()
// columns //
const columns = [ const columns = [
{ title: '序号', key: 'serialNumber', align: 'center', width: 60 }, { title: '序号', key: 'serialNumber', align: 'center', width: 60 },
{ title: '工单号', dataIndex: 'orderNum', key: 'orderNum', align: 'center', width: 120 }, { title: '工单号', dataIndex: 'orderNum', key: 'orderNum', align: 'center', width: 120 },
@ -197,80 +205,56 @@ const columns = [
{ title: '操作', key: 'action', width: 100, fixed: 'right' } { title: '操作', key: 'action', width: 100, fixed: 'right' }
] ]
//
const paginationState = ref({
current: 1,
pageSize: 10,
total: 0,
})
const loading = ref(false)
const listData = ref([])
//
const searchFormData = ref({
name: '',
idCard: '',
exceptionType: undefined,
serviceOrderNo: '',
serviceOrg: undefined,
satisfaction: undefined,
staffSatisfaction: undefined,
isVisited: undefined,
plannedDate: [],
serviceDuration: undefined,
currentNode: [],
})
// //
const advancedSearchVisible = ref([]) const advancedSearchVisible = ref([])
// //
const totalWidth = computed(() => { const totalWidth = computed(() => {
return columns.reduce((sum, col) => sum + (col.width || 100), 0) return columns.reduce((sum, col) => sum + (col.width || 100), 0)
}) })
// a-table // ====== ======
const paginationConfig = computed(() => ({ const showDrawer = ref(false)
current: paginationState.value.current, const currentRecord = ref(null)
pageSize: paginationState.value.pageSize, const staffList = ref([
total: paginationState.value.total, { id: '1', name: '张三' },
showSizeChanger: true, { id: '2', name: '李四' },
showQuickJumper: true, { id: '3', name: '王五' },
})) ])
// //
function mockData() { const drawerInitialValues = computed(() => {
return Array.from({ length: 5 }, (_, i) => ({ if (!currentRecord.value) return {}
id: i + 1, console.log('当前记录传递给抽屉:', currentRecord.value)
orderNum: `GD20251021${String(i + 1).padStart(4, '0')}`,
customerName: `客户${i + 1}`,
idCard: `11010119900101${String(i + 1).padStart(4, '0')}`,
otherPhone1: `1380013800${i}`,
otherPhone2: i % 2 === 0 ? `1390013900${i}` : null,
plannedServiceStartDate: '2025-10-25 09:00:00',
serviceDurationMinutes: 120 + i * 10,
serviceName: '居家照护',
area: '北京市朝阳区',
serviceAddress: '朝阳区某某街道XX号',
creator: '管理员',
createTime: '2025-10-20 14:30:00',
}))
}
// 使 mock return {
id: currentRecord.value.id
}
})
//
async function getPageList() { async function getPageList() {
loading.value = true loading.value = true
try { try {
// showLoading()
await new Promise(resolve => setTimeout(resolve, 300)) const { pageSize, current } = paginationState
listData.value = mockData() const params = {
paginationState.value.total = listData.value.length status:'Initialize',
stationId: storage.local.getItem('stationId'),
companyId: storage.local.getItem('companyId'),
pageSize,
current,
...searchFormData.value
}
const { success, data, total } = await apis.workOrder.getWorkOrderList(params)
listData.value = data
paginationState.total = total
} catch (error) { } catch (error) {
console.error('获取列表失败:', error) console.error('获取工单列表失败:', error)
message.error('加载数据失败') message.error('获取数据失败')
} finally { } finally {
loading.value = false hideLoading()
} }
} }
@ -318,26 +302,14 @@ function formatDate(dateStr) {
return dateStr || '—' return dateStr || '—'
} }
// ====== ====== // ====== ======
const showDrawer = ref(false)
const currentRecord = ref(null)
const staffList = ref([
{ id: '1', name: '张三' },
{ id: '2', name: '李四' },
{ id: '3', name: '王五' },
])
const initialValues = computed(() => {
return {}
})
// ====== ======
function openDispatchDrawer(record) { function openDispatchDrawer(record) {
currentRecord.value = record currentRecord.value = record
showDrawer.value = true showDrawer.value = true
console.log('打开派单抽屉记录ID:', record.id)
} }
function closeDispatchDrawer() { function handleDrawerClose() {
showDrawer.value = false showDrawer.value = false
currentRecord.value = null currentRecord.value = null
} }
@ -346,15 +318,21 @@ function handleDispatchSubmit(values) {
console.log('派单数据:', values) console.log('派单数据:', values)
console.log('派给工单:', currentRecord.value) console.log('派给工单:', currentRecord.value)
//
// await apis.workOrder.dispatchWorkOrder({
// workOrderId: currentRecord.value.id,
// ...values
// })
message.success('派单成功') message.success('派单成功')
closeDispatchDrawer() handleDrawerClose()
//
getPageList()
} }
// //
getPageList() getPageList()
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped></style>