Commit 09609131d9b5854e4b23076303ea2bcf4a2b0cb5

Authored by gesilong
1 parent 9552dd98

commit: 巡检保养相关联调修改

@@ -32,3 +32,23 @@ export const updateInspectionStatus = (params) => { @@ -32,3 +32,23 @@ export const updateInspectionStatus = (params) => {
32 params, 32 params,
33 }); 33 });
34 }; 34 };
  35 +
  36 +/**
  37 + * 详情
  38 + */
  39 +export const getInsPlanDetail = (params) => {
  40 + return defHttp.get<any>({
  41 + url: `/inspectionPlan/detail`,
  42 + params,
  43 + });
  44 +};
  45 +
  46 +/**
  47 + * 更新
  48 + */
  49 +export const updateInsStatus = (params) => {
  50 + return defHttp.post<any>({
  51 + url: `/inspectionPlan/changeStatus`,
  52 + params,
  53 + });
  54 +};
@@ -23,3 +23,22 @@ export const deleteInsRecord = (params) => { @@ -23,3 +23,22 @@ export const deleteInsRecord = (params) => {
23 params, 23 params,
24 }); 24 });
25 }; 25 };
  26 +/**
  27 + * 新增
  28 + */
  29 +export const saveInsRecord = (params) => {
  30 + return defHttp.post<any>({
  31 + url: `/inspectionRecord/save`,
  32 + params,
  33 + });
  34 +};
  35 +
  36 +/**
  37 + * 详情
  38 + */
  39 +export const getInsRecordDetail = (params) => {
  40 + return defHttp.get<any>({
  41 + url: `/inspectionRecord/detail`,
  42 + params,
  43 + });
  44 +};
@@ -24,6 +24,16 @@ export const deleteServePlan = (params) => { @@ -24,6 +24,16 @@ export const deleteServePlan = (params) => {
24 }; 24 };
25 25
26 /** 26 /**
  27 + * 详情
  28 + */
  29 +export const getPreserveDetail = (params) => {
  30 + return defHttp.get<any>({
  31 + url: `/preservePlan/detail`,
  32 + params,
  33 + });
  34 +};
  35 +
  36 +/**
27 * 更新 37 * 更新
28 */ 38 */
29 export const updateServiceStatus = (params) => { 39 export const updateServiceStatus = (params) => {
@@ -32,3 +42,13 @@ export const updateServiceStatus = (params) => { @@ -32,3 +42,13 @@ export const updateServiceStatus = (params) => {
32 params, 42 params,
33 }); 43 });
34 }; 44 };
  45 +
  46 +/**
  47 + * 新增
  48 + */
  49 +export const savePreservePlan = (params) => {
  50 + return defHttp.post<any>({
  51 + url: `/preservePlan/save`,
  52 + params,
  53 + });
  54 +};
@@ -22,3 +22,34 @@ export const deleteServeRecord = (params) => { @@ -22,3 +22,34 @@ export const deleteServeRecord = (params) => {
22 params, 22 params,
23 }); 23 });
24 }; 24 };
  25 +/**
  26 + * 根据保养计划获取保养明细分页接口
  27 + */
  28 +export const serveRecordDetail = (params) => {
  29 + const { page, pageSize } = params;
  30 + const otherParams = omit(params, ['page', 'pageSize']);
  31 + return defHttp.post<any>({
  32 + url: `/preservePlan/pageDetail?page=${page}&pageSize=${pageSize}`,
  33 + params: otherParams,
  34 + });
  35 +};
  36 +
  37 +
  38 +/**
  39 + * 新增
  40 + */
  41 +export const savePreserveRecord = (params) => {
  42 + return defHttp.post<any>({
  43 + url: `/preserveRecord/save`,
  44 + params,
  45 + });
  46 +};
  47 +/**
  48 + * 详情
  49 + */
  50 +export const getRecordDetail = (params) => {
  51 + return defHttp.get<any>({
  52 + url: `/preserveRecord/detail`,
  53 + params,
  54 + });
  55 +};
1 export default { 1 export default {
2 listText: '保养计划', 2 listText: '保养计划',
  3 + preserveDetailText: '保养明细',
3 preserveNameText: '计划名称', 4 preserveNameText: '计划名称',
4 preserveCodeText: '计划编号', 5 preserveCodeText: '计划编号',
5 statusText: '状态', 6 statusText: '状态',
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 ref="tree" 3 ref="tree"
4 class="organization-tree flex relative items-center py-4" 4 class="organization-tree flex relative items-center py-4"
5 :class="foldFlag ? '' : 'pl-4'" 5 :class="foldFlag ? '' : 'pl-4'"
  6 + :style="treeStyle"
6 > 7 >
7 <div 8 <div
8 class="cursor-pointer flex py-4 fold-icon absolute rounded svg:fill-gray-400 hover:bg-gray-200" 9 class="cursor-pointer flex py-4 fold-icon absolute rounded svg:fill-gray-400 hover:bg-gray-200"
@@ -33,8 +34,8 @@ @@ -33,8 +34,8 @@
33 import { useI18n } from '/@/hooks/web/useI18n'; 34 import { useI18n } from '/@/hooks/web/useI18n';
34 35
35 const props = defineProps<OrganizationTreePropsType>(); 36 const props = defineProps<OrganizationTreePropsType>();
36 -  
37 const attrs = useAttrs(); 37 const attrs = useAttrs();
  38 +
38 const tree = ref<Nullable<HTMLDivElement>>(); 39 const tree = ref<Nullable<HTMLDivElement>>();
39 const emit = defineEmits(['select', 'register']); 40 const emit = defineEmits(['select', 'register']);
40 const treeData = ref<TreeItem[]>([]); 41 const treeData = ref<TreeItem[]>([]);
@@ -42,6 +43,7 @@ @@ -42,6 +43,7 @@
42 const treeExpandData = ref<string[]>([]); 43 const treeExpandData = ref<string[]>([]);
43 44
44 const innerProps = ref<OrganizationTreePropsType>({}); 45 const innerProps = ref<OrganizationTreePropsType>({});
  46 + const treeStyle = ref<any>({})
45 47
46 //获取所有父级id 48 //获取所有父级id
47 function findForAllId(data: Recordable[] = [], arr: string[] = []) { 49 function findForAllId(data: Recordable[] = [], arr: string[] = []) {
@@ -59,11 +61,12 @@ @@ -59,11 +61,12 @@
59 selectedKeys.value = []; 61 selectedKeys.value = [];
60 } 62 }
61 63
62 - const foldFlag = ref(true); 64 + const foldFlag = ref(false);
63 const handleFold = () => { 65 const handleFold = () => {
64 foldFlag.value = !unref(foldFlag); 66 foldFlag.value = !unref(foldFlag);
65 }; 67 };
66 68
  69 +
67 const setTreeHeight = () => { 70 const setTreeHeight = () => {
68 const rect = getBoundingClientRect(unref(tree)!); 71 const rect = getBoundingClientRect(unref(tree)!);
69 if (rect) { 72 if (rect) {
@@ -75,6 +78,12 @@ @@ -75,6 +78,12 @@
75 }; 78 };
76 79
77 onMounted(async () => { 80 onMounted(async () => {
  81 + if (attrs?.isOpen) {
  82 + foldFlag.value = false;
  83 + treeStyle.value.height = '50vh'
  84 + }else {
  85 + treeStyle.value.height = '100vh'
  86 + }
78 let api:any; 87 let api:any;
79 if (attrs?.listType === 'equipment') { 88 if (attrs?.listType === 'equipment') {
80 api = getAllCategory() 89 api = getAllCategory()
@@ -128,7 +137,7 @@ @@ -128,7 +137,7 @@
128 137
129 <style scoped lang="less"> 138 <style scoped lang="less">
130 .organization-tree { 139 .organization-tree {
131 - max-height: 100vh; 140 + //max-height: 100vh;
132 141
133 .expand { 142 .expand {
134 opacity: 0; 143 opacity: 0;
  1 +import insPlanModal from './insPlanModal.vue';
  2 +
  3 +export { insPlanModal };
  1 +<template>
  2 + <a-modal
  3 + v-model:visible="visible"
  4 + :title="modalTitle"
  5 + width="80vw"
  6 + @ok="handleOk"
  7 + @cancel="handleCancel"
  8 + >
  9 + <a-form :model="form" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }" style="margin-top: 32px" :rules="rules">
  10 + <a-row :gutter="16">
  11 + <a-col :span="12">
  12 + <a-form-item label="计划编号" name="code">
  13 + <a-input v-model:value="form.code" :disabled="isViewMode" />
  14 + </a-form-item>
  15 + </a-col>
  16 + <a-col :span="12">
  17 + <a-form-item label="计划名称" name="name">
  18 + <a-input v-model:value="form.name" :disabled="isViewMode" />
  19 + </a-form-item>
  20 + </a-col>
  21 + </a-row>
  22 + <a-row :gutter="16">
  23 + <a-col :span="12">
  24 + <a-form-item label="开始时间" name="startTime">
  25 + <a-date-picker
  26 + v-model:value="form.startTime"
  27 + :disabled="isViewMode"
  28 + placeholder="请选择"
  29 + style="width: 100%"
  30 + />
  31 + </a-form-item>
  32 + </a-col>
  33 + <a-col :span="12">
  34 + <a-form-item label="结束时间" name="endTime">
  35 + <a-date-picker
  36 + v-model:value="form.endTime"
  37 + :disabled="isViewMode"
  38 + placeholder="请选择"
  39 + style="width: 100%"
  40 + />
  41 + </a-form-item>
  42 + </a-col>
  43 + </a-row>
  44 + <a-row :gutter="16">
  45 + <a-col :span="12">
  46 + <a-form-item label="计划状态" name="status">
  47 + <a-select
  48 + v-model:value="form.status"
  49 + :disabled="isViewMode"
  50 + placeholder="请选择"
  51 + :options="[
  52 + {label:'未开始',value:'NOT_START'},
  53 + {label:'进行中',value:'UNDERWAY'},
  54 + {label:'已完成',value:'FINISH'},
  55 + {label:'停用',value:'STOP'},
  56 + ]"
  57 + >
  58 + </a-select>
  59 + </a-form-item>
  60 + </a-col>
  61 + </a-row>
  62 + <a-row :gutter="16">
  63 + <a-col :span="24">
  64 + <a-form-item label="计划备注" name="remark">
  65 + <a-textarea
  66 + v-model:value="form.remark"
  67 + :disabled="isViewMode"
  68 + >
  69 + </a-textarea>
  70 + </a-form-item>
  71 + </a-col>
  72 + </a-row>
  73 + <a-form-item label="巡检明细" name="tkCheckDetailsDTOList">
  74 + <div style="text-align: end">
  75 + <a-button class="editable-add-btn" type="primary" @click="handleAdd" style="margin-bottom: 8px" :disabled="isViewMode">
  76 + <template #icon>
  77 + <PlusOutlined/>
  78 + </template>
  79 + 新增
  80 + </a-button>
  81 + <a-table bordered :data-source="tableData" :columns="columns">
  82 + <template #code="{ text, record, index }">
  83 + <div>
  84 + <a-input v-model:value="record.code" :disabled="isViewMode"/>
  85 + </div>
  86 + </template>
  87 + <template #checkDeviceId="{ text, record, index }">
  88 + <div>
  89 + <a-select
  90 + v-model:value="record.checkDeviceId"
  91 + :options="Options"
  92 + :disabled="isViewMode"
  93 + :field-names="{ label: 'name', value: 'id' }"
  94 + placeholder="请选择"
  95 + />
  96 + </div>
  97 + </template>
  98 + <template #checkPlanId="{ text, record, index }">
  99 + <div>
  100 + <a-select
  101 + v-model:value="record.checkPlanId"
  102 + :options="planOptions"
  103 + :disabled="isViewMode"
  104 + :fieldNames="{ label: 'name', value: 'id' }"
  105 + placeholder="请选择"
  106 + />
  107 + </div>
  108 + </template>
  109 + <template #planDetails="{ text, record, index }">
  110 + <div>
  111 + <a-textarea v-model:value="record.planDetails" :disabled="isViewMode"/>
  112 + </div>
  113 + </template>
  114 + <template #operation="{ text, record, index }">
  115 + <div>
  116 + <a-button type="link" @click="handleDelete(index)" :disabled="isViewMode">删除</a-button>
  117 + </div>
  118 + </template>
  119 + </a-table>
  120 + </div>
  121 + </a-form-item>
  122 + </a-form>
  123 + </a-modal>
  124 +</template>
  125 +<script setup lang="ts">
  126 +// 定义 props
  127 +import {onMounted, ref, watch} from "vue";
  128 +import {getLedgerList} from "/@/api/equipment/ledger";
  129 +import {getPlanList} from "/@/api/equipment/chenkPlan";
  130 +const Options = ref([]);
  131 +const planOptions = ref([]);
  132 +const props = defineProps({
  133 + initialData: {
  134 + type: Object,
  135 + default: () => ({
  136 + form: {
  137 + code: '',
  138 + name: '',
  139 + status: '',
  140 + enabled: '',
  141 + startTime: '',
  142 + endTime: '',
  143 + remark: '',
  144 + },
  145 + tableData: [],
  146 + }),
  147 + },
  148 + visible: {
  149 + type: Boolean,
  150 + default: false,
  151 + },
  152 + isViewMode: {
  153 + type: Boolean,
  154 + default: false,
  155 + },
  156 + modalTitle: {
  157 + type: String,
  158 + default: '',
  159 + },
  160 +});
  161 +
  162 +const columns = [
  163 + {
  164 + title: '明细编号',
  165 + dataIndex: 'code',
  166 + slots: { customRender: 'code' },
  167 + width: '160px'
  168 + },
  169 + {
  170 + title: '巡检设备',
  171 + dataIndex: 'checkDeviceId',
  172 + slots: { customRender: 'checkDeviceId' },
  173 + width: '180px'
  174 + },
  175 + {
  176 + title: '巡检方案',
  177 + dataIndex: 'checkPlanId',
  178 + slots: { customRender: 'checkPlanId' },
  179 + width: '180px'
  180 + },
  181 + {
  182 + title: '方案明细',
  183 + dataIndex: 'planDetails',
  184 + slots: { customRender: 'planDetails' },
  185 + width: '160px'
  186 + },
  187 + {
  188 + title: '操作',
  189 + dataIndex: 'operation',
  190 + slots: { customRender: 'operation' },
  191 + width: '120px'
  192 + }
  193 +];
  194 +const rules = {
  195 + code: [
  196 + { required: true, message: '请输入', trigger: 'blur' },
  197 + ],
  198 + name: [
  199 + { required: true, message: '请输入', trigger: 'blur' },
  200 + ],
  201 + remark: [
  202 + { required: true, message: '请输入', trigger: 'blur' },
  203 + ],
  204 + status: [{ required: true, message: '请选择', trigger: 'change' }],
  205 +};
  206 +const visible = ref(props.visible);
  207 +const isViewMode = ref(props.isViewMode);
  208 +const modalTitle = ref(props.modalTitle);
  209 +const form = ref({ ...props.initialData.form });
  210 +const tableData = ref([...props.initialData.tableData]);
  211 +const emit = defineEmits(['update:visible', 'submit']);
  212 +// 监听 visible 的变化
  213 +watch(
  214 + () => props.visible,
  215 + (newVal) => {
  216 + visible.value = newVal;
  217 + }
  218 +);
  219 +
  220 +watch(
  221 + () => props.isViewMode,
  222 + (newVal) => {
  223 + isViewMode.value = newVal;
  224 + }
  225 +);
  226 +
  227 +// 监听 visible 的变化并通知父组件
  228 +watch(
  229 + () => visible.value,
  230 + (newVal) => {
  231 + emit('update:visible', newVal);
  232 + }
  233 +);
  234 +
  235 +// 监听 initialData 的变化
  236 +watch(
  237 + () => props.initialData,
  238 + (newVal) => {
  239 + form.value = { ...newVal.form };
  240 + tableData.value = [...newVal.tableData];
  241 + },
  242 + { deep: true }
  243 +);
  244 +
  245 +
  246 +onMounted(() => {
  247 + fetchAgeOptions();
  248 +});
  249 +
  250 +const fetchAgeOptions = async () => {
  251 + try {
  252 + const response = await getLedgerList({ page: 1, pageSize: 999 }); // 调用接口
  253 + const response1 = await getPlanList({ page: 1, pageSize: 999, type: 'INSPECTION' }); // 调用接口
  254 + Options.value = response.items?.map((item: any) => {
  255 + return {
  256 + value: item?.id,
  257 + label: item?.name
  258 + }
  259 + })
  260 + planOptions.value = response1.items?.map((item: any) => {
  261 + return {
  262 + value: item?.id,
  263 + label: item?.name
  264 + }
  265 + });
  266 + } catch (error) {
  267 + console.error('失败:', error);
  268 + }
  269 +};
  270 +const handleAdd = () => {
  271 + tableData.value.push({
  272 + code: '',
  273 + checkDeviceId: undefined,
  274 + checkPlanId: undefined,
  275 + planDetails: '',
  276 + });
  277 +};
  278 +
  279 +const handleDelete = (index) => {
  280 + tableData.value.splice(index, 1);
  281 +};
  282 +
  283 +const handleOk = () => {
  284 + if (isViewMode.value) {
  285 + visible.value = false;
  286 + return;
  287 + }
  288 + const objData = { ...form.value, tkCheckDetailsDTOList: tableData.value };
  289 + emit('submit', objData); // 将数据提交给父组件
  290 + resetForm();
  291 +}
  292 +
  293 +const handleCancel = () => {
  294 + resetForm();
  295 + visible.value = false;
  296 +};
  297 +// 清空表单和表格数据
  298 +const resetForm = () => {
  299 + form.value = {
  300 + code: '',
  301 + name: '',
  302 + status: '',
  303 + enabled: '',
  304 + startTime: '',
  305 + endTime: '',
  306 + remark: '',
  307 + };
  308 + tableData.value = [];
  309 + isViewMode.value = false;
  310 +};
  311 +</script>
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <BasicTable :clickToRowSelect="false" @register="registerTable"> 3 <BasicTable :clickToRowSelect="false" @register="registerTable">
4 <template #toolbar> 4 <template #toolbar>
5 <Authority value="api:yt:product:category:post"> 5 <Authority value="api:yt:product:category:post">
6 - <Button type="primary"> 6 + <Button type="primary" @click="handleCreate">
7 {{ t('inspection.inspectionPlan.createCategoryText') }} 7 {{ t('inspection.inspectionPlan.createCategoryText') }}
8 </Button> 8 </Button>
9 </Authority> 9 </Authority>
@@ -26,10 +26,16 @@ @@ -26,10 +26,16 @@
26 <TableAction 26 <TableAction
27 :actions="[ 27 :actions="[
28 { 28 {
  29 + label: t('common.viewText'),
  30 + auth: 'api:yt:product:category:update',
  31 + icon: 'ant-design:eye-outlined',
  32 + onClick: handleViewDetail.bind(null, record),
  33 + },
  34 + {
29 label: t('common.editText'), 35 label: t('common.editText'),
30 auth: 'api:yt:product:category:update', 36 auth: 'api:yt:product:category:update',
31 icon: 'clarity:note-edit-line', 37 icon: 'clarity:note-edit-line',
32 - // onClick: handleEdit.bind(null, record), 38 + onClick: handleEdit.bind(null, record),
33 ifShow: () => record.status === 'NOT_START', 39 ifShow: () => record.status === 'NOT_START',
34 }, 40 },
35 { 41 {
@@ -77,17 +83,47 @@ @@ -77,17 +83,47 @@
77 /> 83 />
78 </template> 84 </template>
79 </BasicTable> 85 </BasicTable>
  86 + <insPlanModal
  87 + v-model:visible="modalVisible"
  88 + :initial-data="initialData"
  89 + :is-view-mode="isViewMode"
  90 + @submit="handleSubmit"
  91 + :title="modalTitle"
  92 + />
80 </div> 93 </div>
81 </template> 94 </template>
82 <script setup lang="ts"> 95 <script setup lang="ts">
83 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 96 import { BasicTable, useTable, TableAction } from '/@/components/Table';
84 -import {deleteInspectionPlan, getInspectionPlanList, updateInspectionStatus} from '/@/api/inspection/inspectionPlan'; 97 +import {
  98 + deleteInspectionPlan,
  99 + getInspectionPlanList,
  100 + getInsPlanDetail,
  101 + updateInspectionStatus, updateInsStatus
  102 +} from '/@/api/inspection/inspectionPlan';
85 import { columns, searchFormSchema } from './index'; 103 import { columns, searchFormSchema } from './index';
86 import { useI18n } from '/@/hooks/web/useI18n'; 104 import { useI18n } from '/@/hooks/web/useI18n';
87 -import { Button, Tag } from 'ant-design-vue'; 105 +import {Button, message, Tag} from 'ant-design-vue';
88 import {useMessage} from "/@/hooks/web/useMessage"; 106 import {useMessage} from "/@/hooks/web/useMessage";
  107 +import { insPlanModal } from "./components/index"
  108 +import {ref} from "vue";
  109 +import {dateFormat} from "/@/utils/common/compUtils";
89 const { t } = useI18n(); 110 const { t } = useI18n();
90 const { createMessage } = useMessage(); 111 const { createMessage } = useMessage();
  112 +const modalVisible = ref(false);
  113 +const isViewMode = ref(false);
  114 +const modalTitle = ref('');
  115 +const initialData = ref({
  116 + form: {
  117 + code: '',
  118 + name: '',
  119 + status: '',
  120 + enabled: '',
  121 + startTime: '',
  122 + endTime: '',
  123 + remark: '',
  124 + },
  125 + tableData: [],
  126 +});
91 127
92 const [ 128 const [
93 registerTable, 129 registerTable,
@@ -139,20 +175,21 @@ const handleReload = () => { @@ -139,20 +175,21 @@ const handleReload = () => {
139 }; 175 };
140 176
141 const handleUpdateStatus = async (record?: any,value?: string) => { 177 const handleUpdateStatus = async (record?: any,value?: string) => {
142 - let _status = ''; 178 + let id = record.id;
  179 + let status = '';
143 if (record.status === 'NOT_START') { 180 if (record.status === 'NOT_START') {
144 - _status = 'UNDERWAY' 181 + status = 'UNDERWAY'
145 }else if(record.status === 'UNDERWAY'){ 182 }else if(record.status === 'UNDERWAY'){
146 - _status = 'FINISH' 183 + status = 'FINISH'
147 }else if(record.status === 'FINISH'){ 184 }else if(record.status === 'FINISH'){
148 - _status = 'STOP' 185 + status = 'STOP'
149 } 186 }
150 if (value === 'STOP') { 187 if (value === 'STOP') {
151 - _status = 'STOP' 188 + status = 'STOP'
152 } 189 }
153 try { 190 try {
154 setLoading(true); 191 setLoading(true);
155 - await updateInspectionStatus({ ...record,status: _status }); 192 + await updateInsStatus({ id,status });
156 createMessage.success(t('common.editSuccessText')); 193 createMessage.success(t('common.editSuccessText'));
157 handleReload(); 194 handleReload();
158 } catch (error) { 195 } catch (error) {
@@ -162,4 +199,71 @@ const handleUpdateStatus = async (record?: any,value?: string) => { @@ -162,4 +199,71 @@ const handleUpdateStatus = async (record?: any,value?: string) => {
162 } 199 }
163 } 200 }
164 201
  202 +const handleViewDetail = async (record?: any) => {
  203 + let id = record.id;
  204 + modalTitle.value = '查看';
  205 + try {
  206 + const response = await getInsPlanDetail({id})
  207 + initialData.value = {
  208 + form: response, // 表单数据
  209 + tableData: response.tkCheckDetailsDTOList, // 表格数据
  210 + };
  211 + modalVisible.value = true; // 打开弹框
  212 + isViewMode.value = true;
  213 + }catch (error) {
  214 + throw error;
  215 + }finally {
  216 +
  217 + }
  218 +}
  219 +
  220 +const handleEdit = async (record?: any) => {
  221 + let id = record.id;
  222 + modalTitle.value = '修改';
  223 + try {
  224 + const response = await getInsPlanDetail({id})
  225 + initialData.value = {
  226 + form: response, // 表单数据
  227 + tableData: response.tkCheckDetailsDTOList, // 表格数据
  228 + };
  229 + modalVisible.value = true; // 打开弹框
  230 + }catch (error) {
  231 + throw error;
  232 + }finally {
  233 +
  234 + }
  235 +}
  236 +
  237 +// 新增
  238 +const handleCreate = () => {
  239 + modalTitle.value = '新增';
  240 + initialData.value = {
  241 + form: {
  242 + code: '',
  243 + name: '',
  244 + status: '',
  245 + enabled: '',
  246 + startTime: '',
  247 + endTime: '',
  248 + remark: '',
  249 + },
  250 + tableData: [],
  251 + }
  252 + modalVisible.value = true;
  253 +};
  254 +
  255 +const handleSubmit = async (data) => {
  256 + const format = 'yyyy-MM-dd hh:mm:ss';
  257 + const _data = {
  258 + ...data,
  259 + startTime: dateFormat(data?.startTime, format),
  260 + endTime: dateFormat(data?.endTime, format),
  261 + }
  262 + modalVisible.value = false;
  263 + await updateInspectionStatus(_data)
  264 + message.success('提交成功');
  265 + handleReload()
  266 +};
  267 +
  268 +
165 </script> 269 </script>
  1 +import insRecordModal from './insRecordModal.vue';
  2 +
  3 +export { insRecordModal };
  1 +<template>
  2 + <a-modal
  3 + v-model:visible="visible"
  4 + :title="modalTitle"
  5 + width="80vw"
  6 + @ok="handleOk"
  7 + @cancel="handleCancel"
  8 + >
  9 + <a-form :model="form" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }" style="margin-top: 32px" :rules="rules">
  10 + <a-row :gutter="16">
  11 + <a-col :span="12">
  12 + <a-form-item label="巡检计划" name="inspectionPlanId">
  13 + <a-select
  14 + v-model:value="form.inspectionPlanId"
  15 + :options="planOptions"
  16 + :disabled="isViewMode"
  17 + placeholder="请选择"
  18 + @change="handleChange"
  19 + />
  20 + </a-form-item>
  21 + </a-col>
  22 + <a-col :span="12">
  23 + <a-form-item label="巡检计划编号" name="code">
  24 + <a-input v-model:value="form.code" :disabled="true" />
  25 + </a-form-item>
  26 + </a-col>
  27 + </a-row>
  28 + <a-row :gutter="16">
  29 + <a-col :span="12">
  30 + <a-form-item label="巡检日期" name="checkDate">
  31 + <a-date-picker
  32 + v-model:value="form.checkDate"
  33 + :disabled="isViewMode"
  34 + placeholder="请选择"
  35 + style="width: 100%"
  36 + />
  37 + </a-form-item>
  38 + </a-col>
  39 + <a-col :span="12">
  40 + <a-form-item label="巡检结果" name="recordResult">
  41 + <a-select
  42 + v-model:value="form.recordResult"
  43 + :options="[{label: '正常',value: true},{label: '异常',value: false}]"
  44 + :disabled="isViewMode"
  45 + placeholder="请选择"
  46 + >
  47 + </a-select>
  48 + </a-form-item>
  49 + </a-col>
  50 + </a-row>
  51 + <a-row :gutter="16">
  52 + <a-col :span="12">
  53 + <a-form-item label="巡检人" name="preserveByName">
  54 + <div style="display: flex">
  55 + <a-input
  56 + v-model:value="form.inspectorName"
  57 + placeholder="请选择"
  58 + :disabled="true"
  59 + >
  60 + </a-input>
  61 + <a-button
  62 + type="primary"
  63 + @click="goChoose"
  64 + :disabled="isViewMode"
  65 + >
  66 + 选人
  67 + </a-button>
  68 + </div>
  69 + </a-form-item>
  70 + </a-col>
  71 +
  72 + </a-row>
  73 + <a-form-item label="巡检明细" name="tkInspectionDetailsDTOList">
  74 + <a-table bordered :data-source="tableData" :columns="columns">
  75 + <template #tkDeviceAccountDTO="{ text, record, index }">
  76 + <div>
  77 + {{record?.tkDeviceAccountDTO?.name}}
  78 + </div>
  79 + </template>
  80 + <template #recordResult="{ text, record, index }">
  81 + <div>
  82 + <a-select
  83 + v-model:value="record.recordResult"
  84 + :options="[{label: '正常',value: true},{label: '异常',value: false}]"
  85 + :disabled="isViewMode"
  86 + placeholder="请选择"
  87 + />
  88 + </div>
  89 + </template>
  90 + <template #operation="{ text, record, index }">
  91 + <div>
  92 + <a-button type="link" @click="handleDelete(index)" :disabled="isViewMode">删除</a-button>
  93 + </div>
  94 + </template>
  95 + </a-table>
  96 + </a-form-item>
  97 + </a-form>
  98 + <a-modal
  99 + v-model:visible="userVisible"
  100 + :title="userModalTitle"
  101 + width="60vw"
  102 + height="50vh"
  103 + @ok="handleUserOk"
  104 + @cancel="handleUserCancel"
  105 + >
  106 + <div style="padding: 20px;display: flex">
  107 + <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" isOpen="true"/>
  108 + <div style="margin-top: 20px;margin-left: 30px">
  109 + <a-radio-group v-model:value="selectedItem">
  110 + <template v-for="item in Options" :key="`${item.id}`">
  111 + <a-radio :style="radioStyle" :value="item">{{ item.username }}</a-radio>
  112 + </template>
  113 + </a-radio-group>
  114 + </div>
  115 + </div>
  116 + </a-modal>
  117 + </a-modal>
  118 +</template>
  119 +<script setup lang="ts">
  120 +import {computed, onMounted, reactive, ref, unref, watch} from "vue";
  121 +import {getInspectionPlanList, getInsPlanDetail} from "/@/api/inspection/inspectionPlan";
  122 +import { ApiTreeSelect } from '/@/components/Form';
  123 +import {OrganizationListItem} from "/@/api/system/model/systemModel";
  124 +import {getOrganizationList} from "/@/api/system/system";
  125 +import {getUserListByOrg} from "/@/api/equipment/ledger";
  126 +import {useUserStore} from "/@/store/modules/user";
  127 +import {useI18n} from "/@/hooks/web/useI18n";
  128 +import {useMessage} from "/@/hooks/web/useMessage";
  129 +import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree';
  130 +interface Value {
  131 + value?: string;
  132 + label?: string;
  133 +}
  134 +const rules = {
  135 + code: [{ required: true, message: '请输入', trigger: 'blur' },],
  136 + inspectionPlanId: [{ required: true, message: '请输入', trigger: 'blur' },],
  137 + orgId: [{ required: true, message: '请选择', trigger: 'change' }],
  138 + inspectorId: [{ required: true, message: '请选择', trigger: 'change' }],
  139 + inspectorName: [{ required: true, message: '请选择', trigger: 'change' }],
  140 +
  141 +};
  142 +const columns = [
  143 + {
  144 + title: '巡检设备',
  145 + dataIndex: 'tkDeviceAccountDTO',
  146 + slots: { customRender: 'tkDeviceAccountDTO' },
  147 + width: '180px'
  148 + },
  149 + {
  150 + title: '巡检内容',
  151 + dataIndex: 'planDetails',
  152 + width: '180px'
  153 + },
  154 + {
  155 + title: '巡检结果',
  156 + dataIndex: 'recordResult',
  157 + slots: { customRender: 'recordResult' },
  158 + width: '160px'
  159 + },
  160 + {
  161 + title: '操作',
  162 + dataIndex: 'operation',
  163 + slots: { customRender: 'operation' },
  164 + width: '120px'
  165 + }
  166 +];
  167 +
  168 +const props = defineProps({
  169 + initialData: {
  170 + type: Object,
  171 + default: () => ({
  172 + form: {
  173 + code: '',
  174 + inspectionPlanId: '',
  175 + inspectorId: '',
  176 + inspectorName: '',
  177 + checkDate: '',
  178 + recordResult: '',
  179 + orgId: '',
  180 + },
  181 + tableData: [],
  182 + }),
  183 + },
  184 + visible: {
  185 + type: Boolean,
  186 + default: false,
  187 + },
  188 + isViewMode: {
  189 + type: Boolean,
  190 + default: false,
  191 + },
  192 + modalTitle: {
  193 + type: String,
  194 + default: '',
  195 + },
  196 +});
  197 +const visible = ref(props.visible);
  198 +const isViewMode = ref(props.isViewMode);
  199 +const modalTitle = ref(props.modalTitle);
  200 +const form = ref({ ...props.initialData.form });
  201 +const tableData = ref([...props.initialData.tableData]);
  202 +const emit = defineEmits(['update:visible', 'submit']);
  203 +const planOptions = ref([]);
  204 +const Options = ref([]);
  205 +const userInfo = useUserStore();
  206 +const timespan = ref(Date.now());
  207 +const orgList = ref<Recordable[]>([]);
  208 +const { t } = useI18n();
  209 +const needReload = ref(true);
  210 +
  211 +const { createMessage } = useMessage();
  212 +
  213 +const searchInfo = reactive<Recordable>({});
  214 +const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
  215 +const userVisible = ref(false);
  216 +const userModalTitle = ref('选人');
  217 +const selectedItem = ref<{ id: number; username: string } | null>(null);
  218 +const radioStyle = reactive({
  219 + display: 'block',
  220 + height: '30px',
  221 + lineHeight: '30px',
  222 +});
  223 +
  224 +// 监听 visible 的变化
  225 +watch(
  226 + () => props.visible,
  227 + (newVal) => {
  228 + visible.value = newVal;
  229 + }
  230 +);
  231 +
  232 +watch(
  233 + () => props.isViewMode,
  234 + (newVal) => {
  235 + isViewMode.value = newVal;
  236 + }
  237 +);
  238 +
  239 +// 监听 visible 的变化并通知父组件
  240 +watch(
  241 + () => visible.value,
  242 + (newVal) => {
  243 + emit('update:visible', newVal);
  244 + }
  245 +);
  246 +
  247 +// 监听 initialData 的变化
  248 +watch(
  249 + () => props.initialData,
  250 + (newVal) => {
  251 + console.log(newVal?.form,'66666')
  252 + form.value = { ...newVal.form, inspectorId: newVal.form?.userDTO?.id || '',inspectorName: newVal.form?.userDTO?.realName || ''};
  253 +
  254 + tableData.value = [...newVal.tableData];
  255 + },
  256 + { deep: true }
  257 +);
  258 +
  259 +const goChoose = () => {
  260 + userVisible.value = true;
  261 + selectedItem.value = null;
  262 +}
  263 +
  264 +const handleDelete = (index) => {
  265 + tableData.value.splice(index, 1);
  266 +};
  267 +
  268 +// 确认按钮的回调
  269 +const handleUserOk = () => {
  270 + if (!selectedItem.value) {
  271 + createMessage.warning('请选择一个用户');
  272 + return;
  273 + }
  274 + form.value.inspectorId = selectedItem.value.id
  275 + form.value.inspectorName = selectedItem.value.username
  276 +
  277 + userVisible.value = false; // 关闭弹框
  278 +};
  279 +
  280 +const handleUserCancel = () => {
  281 + selectedItem.value = null;
  282 + userVisible.value = false;
  283 +};
  284 +
  285 +const handleSelect = async (organizationId: string) => {
  286 + searchInfo.organizationId = organizationId;
  287 + const _data = {
  288 + page: '1',
  289 + pageSize: '999',
  290 + tenantId: userInfo.getUserInfo.tenantId!,
  291 + organizationId: organizationId
  292 + }
  293 + const response = await getUserListByOrg(_data); // 调用接口
  294 + Options.value = response.items;
  295 +
  296 +};
  297 +onMounted(() => {
  298 + fetchAgeOptions();
  299 +});
  300 +
  301 +const fetchAgeOptions = async () => {
  302 + try {
  303 + const response = await getInspectionPlanList({ page: 1, pageSize: 999 }); // 调用接口
  304 + planOptions.value = response.items?.map((item: any) => {
  305 + return {
  306 + value: item?.id,
  307 + label: item?.name
  308 + }
  309 + });
  310 + } catch (error) {
  311 + console.error('失败:', error);
  312 + }
  313 +};
  314 +
  315 +const getBindProps = computed<Recordable>(() => {
  316 + const params = {}
  317 + return {
  318 + replaceFields: { children: 'children', key: 'id', title: 'name', value: 'id' },
  319 + getPopupContainer: () => document.body,
  320 + placeholder: t('deviceManagement.device.organizationPlaceholderText'),
  321 + maxLength: 250,
  322 + value: form.orgId,
  323 + dropdownStyle: { maxHeight: '300px' },
  324 + api: async (params: OrganizationListItem) => {
  325 + try {
  326 + const result = ((await getOrganizationList(params)) as unknown as Recordable[]) || [];
  327 + orgList.value = result;
  328 + needReload.value = false;
  329 + return result;
  330 + } catch (error) {
  331 + return unref(orgList);
  332 + }
  333 + },
  334 + params: {
  335 + ...params,
  336 + _t: unref(timespan),
  337 + },
  338 + onChange: async (...args: any[]) => {
  339 + const _data = {
  340 + page: '1',
  341 + pageSize: '999',
  342 + tenantId: userInfo.getUserInfo.tenantId!,
  343 + organizationId: args?.[0]
  344 + }
  345 + const response = await getUserListByOrg(_data); // 调用接口
  346 + Options.value = response.items?.map((item: any) => {
  347 + return {
  348 + label: item.username,
  349 + value: item.id,
  350 + }
  351 + });
  352 + form.orgId.value = args?.[0]
  353 +
  354 + },
  355 + };
  356 +});
  357 +
  358 +const handleChange = async (value: Value) => {
  359 + const res = await getInsPlanDetail({id:value})
  360 + form.value.code = res.code
  361 + tableData.value = res?.tkCheckDetailsDTOList?.map((item: any) => {
  362 + return {
  363 + checkDeviceId: item?.checkDeviceId || '',
  364 + recordResult: true,
  365 + planDetails: item?.checkDeviceId || '',
  366 + tkDeviceAccountDTO: item?.tkDeviceAccountDTO
  367 + }
  368 + }) || []
  369 +};
  370 +
  371 +const handleOk = () => {
  372 + if (isViewMode.value) {
  373 + visible.value = false;
  374 + return;
  375 + }
  376 + const objData = { ...form.value, tkInspectionDetailsDTOList: tableData.value };
  377 + emit('submit', objData); // 将数据提交给父组件
  378 + resetForm();
  379 +}
  380 +const handleCancel = () => {
  381 + resetForm();
  382 + visible.value = false;
  383 +}
  384 +
  385 +// 清空表单和表格数据
  386 +const resetForm = () => {
  387 + form.value = {
  388 + code: '',
  389 + inspectionPlanId: '',
  390 + inspectorId: '',
  391 + inspectorName: '',
  392 + checkDate: '',
  393 + recordResult: '',
  394 + orgId: '',
  395 + };
  396 + tableData.value = [];
  397 + isViewMode.value = false;
  398 +};
  399 +
  400 +</script>
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <BasicTable :clickToRowSelect="false" @register="registerTable"> 3 <BasicTable :clickToRowSelect="false" @register="registerTable">
4 <template #toolbar> 4 <template #toolbar>
5 <Authority value="api:yt:product:category:post"> 5 <Authority value="api:yt:product:category:post">
6 - <Button type="primary" > 6 + <Button type="primary" @click="handleCreate">
7 {{ t('inspection.inspectionRecord.createRecordText') }} 7 {{ t('inspection.inspectionRecord.createRecordText') }}
8 </Button> 8 </Button>
9 </Authority> 9 </Authority>
@@ -20,10 +20,16 @@ @@ -20,10 +20,16 @@
20 <TableAction 20 <TableAction
21 :actions="[ 21 :actions="[
22 { 22 {
  23 + label: t('common.viewText'),
  24 + auth: 'api:yt:product:category:update',
  25 + icon: 'ant-design:eye-outlined',
  26 + onClick: handleViewDetail.bind(null, record),
  27 + },
  28 + {
23 label: t('common.editText'), 29 label: t('common.editText'),
24 auth: 'api:yt:product:category:update', 30 auth: 'api:yt:product:category:update',
25 icon: 'clarity:note-edit-line', 31 icon: 'clarity:note-edit-line',
26 - // onClick: handleEdit.bind(null, record), 32 + onClick: handleEdit.bind(null, record),
27 }, 33 },
28 { 34 {
29 label: t('common.delText'), 35 label: t('common.delText'),
@@ -39,18 +45,46 @@ @@ -39,18 +45,46 @@
39 /> 45 />
40 </template> 46 </template>
41 </BasicTable> 47 </BasicTable>
  48 + <insRecordModal
  49 + v-model:visible="modalVisible"
  50 + :initial-data="initialData"
  51 + :is-view-mode="isViewMode"
  52 + :title="modalTitle"
  53 + @submit="handleSubmit"
  54 + />
42 </div> 55 </div>
43 </template> 56 </template>
44 <script setup lang="ts"> 57 <script setup lang="ts">
  58 + import {ref} from "vue";
45 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 59 import { BasicTable, useTable, TableAction } from '/@/components/Table';
46 - import { getInspectionRecordList, deleteInsRecord } from '/@/api/inspection/inspectionRecord'; 60 + import {
  61 + getInspectionRecordList,
  62 + deleteInsRecord,
  63 + saveInsRecord, getInsRecordDetail
  64 + } from '/@/api/inspection/inspectionRecord';
47 import { columns, searchFormSchema } from './index'; 65 import { columns, searchFormSchema } from './index';
48 import { useI18n } from '/@/hooks/web/useI18n'; 66 import { useI18n } from '/@/hooks/web/useI18n';
49 - import { Button, Tag } from 'ant-design-vue'; 67 + import {Button, message, Tag} from 'ant-design-vue';
50 import {useMessage} from "/@/hooks/web/useMessage"; 68 import {useMessage} from "/@/hooks/web/useMessage";
  69 + import { insRecordModal } from "./components/index"
51 const { t } = useI18n(); 70 const { t } = useI18n();
52 const { createMessage } = useMessage(); 71 const { createMessage } = useMessage();
53 - 72 + const modalVisible = ref(false);
  73 + const isViewMode = ref(false);
  74 + const modalTitle = ref('');
  75 + import { dateFormat } from '/@/utils/common/compUtils';
  76 + import {getRecordDetail} from "/@/api/inspection/serviceRecord";
  77 + const initialData = ref({
  78 + form: {
  79 + code: '',
  80 + inspectionPlanId: '',
  81 + inspectorId: '',
  82 + checkDate: '',
  83 + recordResult: '',
  84 + orgId: '',
  85 + },
  86 + tableData: [],
  87 + });
54 const [ 88 const [
55 registerTable, 89 registerTable,
56 { reload, setLoading, getSelectRowKeys, setSelectedRowKeys, getRowSelection }, 90 { reload, setLoading, getSelectRowKeys, setSelectedRowKeys, getRowSelection },
@@ -95,8 +129,71 @@ @@ -95,8 +129,71 @@
95 } 129 }
96 }; 130 };
97 131
  132 + const handleCreate = () => {
  133 + modalTitle.value = '新增';
  134 + initialData.value = {
  135 + form: {
  136 + code: '',
  137 + inspectionPlanId: '',
  138 + inspectorId: '',
  139 + checkDate: '',
  140 + recordResult: '',
  141 + orgId: '',
  142 + },
  143 + tableData: [],
  144 + }
  145 + modalVisible.value = true;
  146 + }
  147 +
98 const handleReload = () => { 148 const handleReload = () => {
99 setSelectedRowKeys([]); 149 setSelectedRowKeys([]);
100 reload(); 150 reload();
101 }; 151 };
  152 +
  153 + const handleSubmit = async (data) => {
  154 + const format = 'yyyy-MM-dd hh:mm:ss';
  155 + modalVisible.value = false;
  156 + const _data = {
  157 + ...data,
  158 + checkDate: dateFormat(data?.checkDate, format)
  159 + }
  160 + await saveInsRecord(_data)
  161 + message.success('提交成功');
  162 + handleReload()
  163 + };
  164 +
  165 + const handleViewDetail = async (record?: any) => {
  166 + let id = record.id;
  167 + modalTitle.value = '查看';
  168 + try {
  169 + const response = await getInsRecordDetail({id})
  170 + initialData.value = {
  171 + form: response, // 表单数据
  172 + tableData: response.tkInspectionDetailsDTOList, // 表格数据
  173 + };
  174 + modalVisible.value = true; // 打开弹框
  175 + isViewMode.value = true;
  176 + }catch (error) {
  177 + throw error;
  178 + }finally {
  179 +
  180 + }
  181 + }
  182 +
  183 + const handleEdit = async (record?: any) => {
  184 + let id = record.id;
  185 + modalTitle.value = '修改';
  186 + try {
  187 + const response = await getInsRecordDetail({id})
  188 + initialData.value = {
  189 + form: response, // 表单数据
  190 + tableData: response.tkInspectionDetailsDTOList, // 表格数据
  191 + };
  192 + modalVisible.value = true; // 打开弹框
  193 + }catch (error) {
  194 + throw error;
  195 + }finally {
  196 + }
  197 + }
  198 +
102 </script> 199 </script>
1 <template> 1 <template>
2 - <div>  
3 - <BasicModal  
4 - v-bind="$attrs"  
5 - width="30rem"  
6 - :title="getTitle"  
7 - @register="register"  
8 - @cancel="handleCancel"  
9 - @ok="handleOk"  
10 - destroyOnClose  
11 - >  
12 - <div>  
13 - <BasicForm @register="registerForm" />  
14 - </div>  
15 - </BasicModal>  
16 - </div> 2 + <a-modal
  3 + v-model:visible="visible"
  4 + :title="modalTitle"
  5 + width="80vw"
  6 + @ok="handleOk"
  7 + @cancel="handleCancel"
  8 + >
  9 + <a-form :model="form" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }" style="margin-top: 32px" :rules="rules">
  10 + <a-row :gutter="16">
  11 + <a-col :span="12">
  12 + <a-form-item label="计划编号" name="preserveCode">
  13 + <a-input v-model:value="form.preserveCode" :disabled="isViewMode" />
  14 + </a-form-item>
  15 + </a-col>
  16 + <a-col :span="12">
  17 + <a-form-item label="计划名称" name="preserveName">
  18 + <a-input v-model:value="form.preserveName" :disabled="isViewMode" />
  19 + </a-form-item>
  20 + </a-col>
  21 + </a-row>
  22 + <a-row :gutter="16">
  23 + <a-col :span="12">
  24 + <a-form-item label="保养设备" name="status">
  25 + <a-select
  26 + v-model:value="form.status"
  27 + :options="statusOptions"
  28 + :disabled="isViewMode"
  29 + placeholder="请选择"
  30 + />
  31 + </a-form-item>
  32 + </a-col>
  33 + <a-col :span="12">
  34 + <a-form-item label="次数" name="times">
  35 + <a-input v-model:value="form.times" :disabled="isViewMode" />
  36 + </a-form-item>
  37 + </a-col>
  38 + </a-row>
  39 + <a-row :gutter="16">
  40 + <a-col :span="12">
  41 + <a-form-item label="频率" name="frequency">
  42 + <a-input v-model:value="form.frequency" :disabled="isViewMode" />
  43 + </a-form-item>
  44 + </a-col>
  45 + </a-row>
  46 + <a-form-item label="保养明细" name="preserveDetailList">
  47 + <div style="text-align: end">
  48 + <a-button class="editable-add-btn" type="primary" @click="handleAdd" style="margin-bottom: 8px" :disabled="isViewMode">
  49 + <template #icon>
  50 + <PlusOutlined/>
  51 + </template>
  52 + 新增
  53 + </a-button>
  54 + </div>
  55 + <a-table bordered :data-source="tableData" :columns="columns">
  56 + <template #detailCode="{ text, record, index }">
  57 + <div>
  58 + <a-input v-model:value="record.detailCode" :disabled="isViewMode"/>
  59 + </div>
  60 + </template>
  61 + <template #deviceId="{ text, record, index }">
  62 + <div>
  63 + <a-select
  64 + v-model:value="record.deviceId"
  65 + :options="Options"
  66 + :disabled="isViewMode"
  67 + :field-names="{ label: 'name', value: 'id' }"
  68 + placeholder="请选择"
  69 + />
  70 + </div>
  71 + </template>
  72 + <template #checkPlanId="{ text, record, index }">
  73 + <div>
  74 + <a-select
  75 + v-model:value="record.checkPlanId"
  76 + :options="planOptions"
  77 + :disabled="isViewMode"
  78 + :fieldNames="{ label: 'name', value: 'id' }"
  79 + placeholder="请选择"
  80 + />
  81 + </div>
  82 + </template>
  83 + <template #preserveDetail="{ text, record, index }">
  84 + <div>
  85 + <a-textarea v-model:value="record.preserveDetail" :disabled="isViewMode"/>
  86 + </div>
  87 + </template>
  88 + <template #operation="{ text, record, index }">
  89 + <div>
  90 + <a-button type="link" @click="handleDelete(index)" :disabled="isViewMode">删除</a-button>
  91 + </div>
  92 + </template>
  93 + </a-table>
  94 + </a-form-item>
  95 + </a-form>
  96 + </a-modal>
17 </template> 97 </template>
  98 +
18 <script setup lang="ts"> 99 <script setup lang="ts">
19 -import {computed, ref, unref} from "vue";  
20 -import {useI18n} from "/@/hooks/web/useI18n";  
21 -import {useForm} from "/@/components/Form";  
22 -import {schemas} from "../index";  
23 -import {useModalInner} from "/@/components/Modal"; 100 +import { ref, onMounted, watch } from 'vue';
  101 +import { getLedgerList } from "/@/api/equipment/ledger";
  102 +import { getPlanList } from "/@/api/equipment/chenkPlan";
  103 +import { useI18n } from "/@/hooks/web/useI18n";
  104 +import { message } from 'ant-design-vue';
  105 +
  106 +
  107 +const Options = ref([]);
  108 +const planOptions = ref([]);
24 const { t } = useI18n(); 109 const { t } = useI18n();
25 -const isUpdate = ref<Boolean>(false);  
26 -const recordInfo = ref<any>({});  
27 -const emit = defineEmits(['handleReload', 'register']);  
28 -  
29 -const getTitle = computed(() =>  
30 - !unref(isUpdate)  
31 - ? t('inspection.servicePlan.createPlanText')  
32 - : t('inspection.servicePlan.editPlanText') 110 +// 定义 props
  111 +const props = defineProps({
  112 + initialData: {
  113 + type: Object,
  114 + default: () => ({
  115 + form: {
  116 + preserveCode: '',
  117 + preserveName: '',
  118 + status: '',
  119 + times: '',
  120 + frequency: '',
  121 + },
  122 + tableData: [],
  123 + }),
  124 + },
  125 + visible: {
  126 + type: Boolean,
  127 + default: false,
  128 + },
  129 + isViewMode: {
  130 + type: Boolean,
  131 + default: false,
  132 + },
  133 + modalTitle: {
  134 + type: String,
  135 + default: '',
  136 + },
  137 +});
  138 +const visible = ref(props.visible);
  139 +const isViewMode = ref(props.isViewMode);
  140 +const modalTitle = ref(props.modalTitle);
  141 +const rules = {
  142 + preserveCode: [
  143 + { required: true, message: '请输入', trigger: 'blur' },
  144 + ],
  145 + preserveName: [
  146 + { required: true, message: '请输入', trigger: 'blur' },
  147 + ],
  148 +
  149 + frequency: [
  150 + { required: true, message: '请输入', trigger: 'blur' },
  151 + ],
  152 +
  153 + times: [
  154 + { required: true, message: '请输入', trigger: 'blur' },
  155 + ],
  156 + status: [{ required: true, message: '请选择', trigger: 'change' }],
  157 + preserveDetailList: [{ required: true, message: '请选择', trigger: 'change' }],
  158 +
  159 +};
  160 +
  161 +const statusOptions = [
  162 + { label: t('inspection.servicePlan.NOTSTART'), value: 'NOTSTART' },
  163 + { label: t('inspection.servicePlan.UNDERWAY'), value: 'UNDERWAY' },
  164 + { label: t('inspection.servicePlan.COMPLETED'), value: 'COMPLETED' },
  165 + { label: t('inspection.servicePlan.STOP'), value: 'STOP' },
  166 +];
  167 +const form = ref({ ...props.initialData.form });
  168 +const tableData = ref([...props.initialData.tableData]);
  169 +const emit = defineEmits(['update:visible', 'submit']);
  170 +onMounted(() => {
  171 + fetchAgeOptions();
  172 +});
  173 +
  174 +const fetchAgeOptions = async () => {
  175 + try {
  176 + const response = await getLedgerList({ page: 1, pageSize: 999 }); // 调用接口
  177 + const response1 = await getPlanList({ page: 1, pageSize: 999, type: 'MAINTENANCE' }); // 调用接口
  178 + Options.value = response.items?.map((item: any) => {
  179 + return {
  180 + value: item?.id,
  181 + label: item?.name
  182 + }
  183 + })
  184 + planOptions.value = response1.items?.map((item: any) => {
  185 + return {
  186 + value: item?.id,
  187 + label: item?.name
  188 + }
  189 + });
  190 + } catch (error) {
  191 + console.error('失败:', error);
  192 + }
  193 +};
  194 +
  195 +// 监听 visible 的变化
  196 +watch(
  197 + () => props.visible,
  198 + (newVal) => {
  199 + visible.value = newVal;
  200 + }
33 ); 201 );
34 202
35 -const [registerForm, { getFieldsValue, setFieldsValue, validate, updateSchema }] = useForm({  
36 - labelWidth: 140,  
37 - schemas,  
38 - actionColOptions: {  
39 - span: 14, 203 +watch(
  204 + () => props.isViewMode,
  205 + (newVal) => {
  206 + isViewMode.value = newVal;
  207 + }
  208 +);
  209 +
  210 +// 监听 visible 的变化并通知父组件
  211 +watch(
  212 + () => visible.value,
  213 + (newVal) => {
  214 + emit('update:visible', newVal);
  215 + }
  216 +);
  217 +
  218 +// 监听 initialData 的变化
  219 +watch(
  220 + () => props.initialData,
  221 + (newVal) => {
  222 + form.value = { ...newVal.form };
  223 + tableData.value = [...newVal.tableData];
40 }, 224 },
41 - showActionButtonGroup: false,  
42 -}); 225 + { deep: true }
  226 +);
43 227
44 -const [register, { closeModal, setModalProps }] = useModalInner(async (data) => {  
45 - setModalProps({ confirmLoading: false, loading: true });  
46 - isUpdate.value = data?.isUpdate;  
47 - recordInfo.value = data?.record;  
48 - if (data?.record) {  
49 - setFieldsValue(data?.record); 228 +const columns = [
  229 + {
  230 + title: '明细编号',
  231 + dataIndex: 'detailCode',
  232 + slots: { customRender: 'detailCode' },
  233 + width: '160px'
  234 + },
  235 + {
  236 + title: '保养设备',
  237 + dataIndex: 'deviceId',
  238 + slots: { customRender: 'deviceId' },
  239 + width: '180px'
  240 + },
  241 + {
  242 + title: '保养方案',
  243 + dataIndex: 'checkPlanId',
  244 + slots: { customRender: 'checkPlanId' },
  245 + width: '180px'
  246 + },
  247 + {
  248 + title: '方案明细',
  249 + dataIndex: 'preserveDetail',
  250 + slots: { customRender: 'preserveDetail' },
  251 + width: '160px'
  252 + },
  253 + {
  254 + title: '操作',
  255 + dataIndex: 'operation',
  256 + slots: { customRender: 'operation' },
  257 + width: '120px'
50 } 258 }
51 - setModalProps({ loading: false });  
52 -}); 259 +];
53 260
54 -const handleCancel = () => {  
55 - closeModal(); 261 +const handleAdd = () => {
  262 + tableData.value.push({
  263 + detailCode: '',
  264 + deviceId: undefined,
  265 + checkPlanId: undefined,
  266 + preserveDetail: '',
  267 + });
56 }; 268 };
57 269
58 -const handleOk = async () => { 270 +const handleDelete = (index) => {
  271 + tableData.value.splice(index, 1);
  272 +};
  273 +
  274 +const handleOk = () => {
  275 + if (isViewMode.value) {
  276 + visible.value = false;
  277 + return;
  278 + }
  279 + const objData = { ...form.value, preserveDetailList: tableData.value };
  280 + emit('submit', objData); // 将数据提交给父组件
  281 + resetForm();
  282 +};
59 283
60 -} 284 +const handleCancel = () => {
  285 + resetForm();
  286 + visible.value = false;
  287 +};
  288 +// 清空表单和表格数据
  289 +const resetForm = () => {
  290 + form.value = {
  291 + serveCode: '',
  292 + preserveName: '',
  293 + status: '',
  294 + times: '',
  295 + frequency: '',
  296 +};
  297 + tableData.value = [];
  298 + isViewMode.value = false;
  299 +};
61 </script> 300 </script>
1 -import { FormSchema } from '/@/components/Form'; 1 +import {FormSchema} from '/@/components/Form';
2 import { useI18n } from '/@/hooks/web/useI18n'; 2 import { useI18n } from '/@/hooks/web/useI18n';
3 import { BasicColumn } from '/@/components/Table'; 3 import { BasicColumn } from '/@/components/Table';
4 const { t } = useI18n(); 4 const { t } = useI18n();
5 5
  6 +
6 export const searchFormSchema: FormSchema[] = [ 7 export const searchFormSchema: FormSchema[] = [
7 { 8 {
8 field: 'preserveName', 9 field: 'preserveName',
9 label: t('inspection.servicePlan.preserveNameText'), 10 label: t('inspection.servicePlan.preserveNameText'),
10 component: 'Input', 11 component: 'Input',
11 - colProps: { span: 8 }, 12 + colProps: { span: 6 },
12 }, 13 },
13 ]; 14 ];
14 15
@@ -37,49 +38,4 @@ export const columns: BasicColumn[] = [ @@ -37,49 +38,4 @@ export const columns: BasicColumn[] = [
37 ]; 38 ];
38 39
39 40
40 -export const schemas: FormSchema[] = [  
41 - {  
42 - field: 'code',  
43 - label: t('equipment.checkPlan.nameCode'),  
44 - component: 'Input',  
45 - colProps: { span: 21 },  
46 - required: true,  
47 - componentProps: {  
48 - maxLength: 20,  
49 - },  
50 - },  
51 - {  
52 - field: 'name',  
53 - label: t('equipment.checkPlan.nameText'),  
54 - component: 'Input',  
55 - colProps: { span: 21 },  
56 - required: true,  
57 - componentProps: {  
58 - maxLength: 20,  
59 - },  
60 - },  
61 - {  
62 - field: 'type',  
63 - label: t('equipment.checkPlan.typeText'),  
64 - component: 'RadioButtonGroup',  
65 - defaultValue: 'INSPECTION',  
66 41
67 - },  
68 - {  
69 - field: 'status',  
70 - label: t('equipment.checkPlan.statusText'),  
71 - component: 'RadioButtonGroup',  
72 - defaultValue: 'ENABLE',  
73 -  
74 - },  
75 - {  
76 - field: 'planDetails',  
77 - label: t('equipment.checkPlan.nameDetail'),  
78 - component: 'InputTextArea',  
79 - colProps: { span: 21 },  
80 - required: true,  
81 - componentProps: {  
82 - maxLength: 200,  
83 - },  
84 - },  
85 -];  
@@ -26,10 +26,16 @@ @@ -26,10 +26,16 @@
26 <TableAction 26 <TableAction
27 :actions="[ 27 :actions="[
28 { 28 {
  29 + label: t('common.viewText'),
  30 + auth: 'api:yt:product:category:update',
  31 + icon: 'ant-design:eye-outlined',
  32 + onClick: handleViewDetail.bind(null, record),
  33 + },
  34 + {
29 label: t('common.editText'), 35 label: t('common.editText'),
30 auth: 'api:yt:product:category:update', 36 auth: 'api:yt:product:category:update',
31 icon: 'clarity:note-edit-line', 37 icon: 'clarity:note-edit-line',
32 - // onClick: handleEdit.bind(null, record), 38 + onClick: handleEdit.bind(null, record),
33 ifShow: () => record.status === 'NOTSTART', 39 ifShow: () => record.status === 'NOTSTART',
34 }, 40 },
35 { 41 {
@@ -77,22 +83,43 @@ @@ -77,22 +83,43 @@
77 /> 83 />
78 </template> 84 </template>
79 </BasicTable> 85 </BasicTable>
80 - <servicePlanModal @register="registerModal" @handleReload="handleReload" /> 86 + <servicePlanModal
  87 + v-model:visible="modalVisible"
  88 + :initial-data="initialData"
  89 + :is-view-mode="isViewMode"
  90 + @submit="handleSubmit"
  91 + :title="modalTitle"
  92 + />
81 93
82 </div> 94 </div>
83 </template> 95 </template>
84 <script setup lang="ts"> 96 <script setup lang="ts">
85 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 97 import { BasicTable, useTable, TableAction } from '/@/components/Table';
86 - import {deleteServePlan, getServicePlanList, updateServiceStatus} from '/@/api/inspection/servicePlan'; 98 + import {deleteServePlan, getServicePlanList, updateServiceStatus, savePreservePlan, getPreserveDetail} from '/@/api/inspection/servicePlan';
  99 + import { servicePlanModal } from "./components/index"
87 import { columns, searchFormSchema } from './index'; 100 import { columns, searchFormSchema } from './index';
88 import { useI18n } from '/@/hooks/web/useI18n'; 101 import { useI18n } from '/@/hooks/web/useI18n';
89 - import { Button, Tag } from 'ant-design-vue'; 102 + import {Button, message, Tag} from 'ant-design-vue';
90 import {useModal} from "/@/components/Modal"; 103 import {useModal} from "/@/components/Modal";
91 import {useMessage} from "/@/hooks/web/useMessage"; 104 import {useMessage} from "/@/hooks/web/useMessage";
92 const { t } = useI18n(); 105 const { t } = useI18n();
  106 + import { ref } from "vue"
  107 + import {getPreservePlanDetail} from "/@/api/inspection/inspectionPlan";
93 const [registerModal, { openModal }] = useModal(); 108 const [registerModal, { openModal }] = useModal();
94 const { createMessage } = useMessage(); 109 const { createMessage } = useMessage();
95 - 110 + const modalVisible = ref(false);
  111 + const isViewMode = ref(false);
  112 + const modalTitle = ref('');
  113 + const initialData = ref({
  114 + form: {
  115 + preserveCode: '',
  116 + preserveName: '',
  117 + status: '',
  118 + times: '',
  119 + frequency: '',
  120 + },
  121 + tableData: [],
  122 + });
96 const [ 123 const [
97 registerTable, 124 registerTable,
98 { reload, setLoading, getSelectRowKeys, setSelectedRowKeys, getRowSelection }, 125 { reload, setLoading, getSelectRowKeys, setSelectedRowKeys, getRowSelection },
@@ -125,9 +152,27 @@ @@ -125,9 +152,27 @@
125 152
126 // 新增 153 // 新增
127 const handleCreate = () => { 154 const handleCreate = () => {
128 - openModal(true, {  
129 - isUpdate: false,  
130 - }); 155 + modalTitle.value = '新增';
  156 + initialData.value = {
  157 + form: {
  158 + preserveCode: '',
  159 + preserveName: '',
  160 + status: '',
  161 + times: '',
  162 + frequency: '',
  163 + },
  164 + tableData: [],
  165 + }
  166 + modalVisible.value = true;
  167 + };
  168 +
  169 + const handleSubmit = async (data) => {
  170 + console.log('提交的数据:', data);
  171 +
  172 + modalVisible.value = false;
  173 + await savePreservePlan(data)
  174 + message.success('提交成功');
  175 + handleReload()
131 }; 176 };
132 177
133 const handleReload = () => { 178 const handleReload = () => {
@@ -135,6 +180,41 @@ @@ -135,6 +180,41 @@
135 reload(); 180 reload();
136 }; 181 };
137 182
  183 + const handleViewDetail = async (record?: any) => {
  184 + let id = record.id;
  185 + modalTitle.value = '查看';
  186 + try {
  187 + const response = await getPreserveDetail({id})
  188 + initialData.value = {
  189 + form: response, // 表单数据
  190 + tableData: response.preserveDetailList, // 表格数据
  191 + };
  192 + modalVisible.value = true; // 打开弹框
  193 + isViewMode.value = true;
  194 + }catch (error) {
  195 + throw error;
  196 + }finally {
  197 +
  198 + }
  199 + }
  200 +
  201 + const handleEdit = async (record?: any) => {
  202 + let id = record.id;
  203 + modalTitle.value = '修改';
  204 + try {
  205 + const response = await getPreserveDetail({id})
  206 + initialData.value = {
  207 + form: response, // 表单数据
  208 + tableData: response.preserveDetailList, // 表格数据
  209 + };
  210 + modalVisible.value = true; // 打开弹框
  211 + }catch (error) {
  212 + throw error;
  213 + }finally {
  214 +
  215 + }
  216 + }
  217 +
138 const handleDelete = async (record?: any) => { 218 const handleDelete = async (record?: any) => {
139 let id = record.id; 219 let id = record.id;
140 try { 220 try {
  1 +import serviceRecordModal from './serviceRecordModal.vue';
  2 +
  3 +export { serviceRecordModal };
  1 +<template>
  2 + <a-modal
  3 + v-model:visible="visible"
  4 + :title="modalTitle"
  5 + width="80vw"
  6 + @ok="handleOk"
  7 + @cancel="handleCancel"
  8 + >
  9 + <a-form :model="form" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }" style="margin-top: 32px" :rules="rules">
  10 + <a-row :gutter="16">
  11 + <a-col :span="12">
  12 + <a-form-item label="记录编号" name="recordCode">
  13 + <a-input v-model:value="form.recordCode" :disabled="isViewMode" />
  14 + </a-form-item>
  15 + </a-col>
  16 + <a-col :span="12">
  17 + <a-form-item label="保养计划" name="preservePlanId">
  18 + <a-select
  19 + v-model:value="form.preservePlanId"
  20 + :options="planOptions"
  21 + :disabled="isViewMode"
  22 + placeholder="请选择"
  23 + @change="handleChange"
  24 + />
  25 + </a-form-item>
  26 + </a-col>
  27 + </a-row>
  28 +
  29 + <a-row :gutter="16">
  30 + <a-col :span="12">
  31 + <a-form-item label="保养日期" name="preserveDate">
  32 + <a-date-picker
  33 + v-model:value="form.preserveDate"
  34 + :disabled="isViewMode"
  35 + placeholder="请选择"
  36 + style="width: 100%"
  37 + />
  38 + </a-form-item>
  39 + </a-col>
  40 + <a-col :span="12">
  41 + <a-form-item label="维护结果" name="preserveStatus">
  42 + <a-select
  43 + v-model:value="form.preserveStatus"
  44 + :disabled="isViewMode"
  45 + placeholder="请选择"
  46 + :options="[{label:'未完成',value:'INCOMPLETE'},{label:'已完成',value:'COMPLETE'}]"
  47 + ></a-select>
  48 + </a-form-item>
  49 + </a-col>
  50 + </a-row>
  51 + <a-row :gutter="16">
  52 + <a-col :span="12">
  53 + <a-form-item label="保养人" name="preserveByName">
  54 + <div style="display: flex">
  55 + <a-input
  56 + v-model:value="form.preserveByName"
  57 + placeholder="请选择"
  58 + :disabled="true"
  59 + >
  60 + </a-input>
  61 + <a-button
  62 + type="primary"
  63 + @click="goChoose"
  64 + :disabled="isViewMode"
  65 + >
  66 + 选人
  67 + </a-button>
  68 + </div>
  69 +
  70 + </a-form-item>
  71 + </a-col>
  72 + </a-row>
  73 + <a-form-item label="保养明细" name="preserveDetailList">
  74 + <a-table bordered :data-source="tableData" :columns="columns">
  75 + <template #deviceInfo="{ text, record, index }">
  76 + <div>
  77 + {{record?.deviceInfo.name}}
  78 + </div>
  79 + </template>
  80 + <template #status="{ text, record, index }">
  81 + <div>
  82 + <a-select
  83 + v-model:value="record.status"
  84 + :options="defaultOptions"
  85 + :disabled="isViewMode"
  86 + :field-names="{ label: 'name', value: 'id' }"
  87 + placeholder="请选择"
  88 + />
  89 + </div>
  90 + </template>
  91 + <template #operation="{ text, record, index }">
  92 + <div>
  93 + <a-button type="link" @click="handleDelete(index)" :disabled="isViewMode">删除</a-button>
  94 + </div>
  95 + </template>
  96 + </a-table>
  97 + </a-form-item>
  98 + </a-form>
  99 + <a-modal
  100 + v-model:visible="userVisible"
  101 + :title="userModalTitle"
  102 + width="60vw"
  103 + height="50vh"
  104 + @ok="handleUserOk"
  105 + @cancel="handleUserCancel"
  106 + >
  107 + <div style="padding: 20px;display: flex">
  108 + <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" isOpen="true"/>
  109 + <div style="margin-top: 20px;margin-left: 30px">
  110 + <a-radio-group v-model:value="selectedItem">
  111 + <template v-for="item in Options" :key="`${item.id}`">
  112 + <a-radio :style="radioStyle" :value="item">{{ item.username }}</a-radio>
  113 + </template>
  114 + </a-radio-group>
  115 + </div>
  116 + </div>
  117 + </a-modal>
  118 + </a-modal>
  119 +</template>
  120 +<script setup lang="ts">
  121 +// 定义 props
  122 +import {computed, onMounted, ref, unref, watch, reactive} from "vue";
  123 +import {getServicePlanList} from "/@/api/inspection/servicePlan";
  124 +import { ApiTreeSelect } from '/@/components/Form';
  125 +import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree';
  126 +import {OrganizationListItem} from "/@/api/system/model/systemModel";
  127 +import {getOrganizationList} from "/@/api/system/system";
  128 +import {useI18n} from "/@/hooks/web/useI18n";
  129 +import {getUserListByOrg} from "/@/api/equipment/ledger";
  130 +import {useUserStore} from "/@/store/modules/user";
  131 +import {serveRecordDetail} from "/@/api/inspection/serviceRecord";
  132 +import {useMessage} from "/@/hooks/web/useMessage";
  133 +const { createMessage } = useMessage();
  134 +
  135 +const searchInfo = reactive<Recordable>({});
  136 +const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
  137 +const userVisible = ref(false);
  138 +const userModalTitle = ref('选人');
  139 +const selectedItem = ref<{ id: number; username: string } | null>(null);
  140 +const radioStyle = reactive({
  141 + display: 'block',
  142 + height: '30px',
  143 + lineHeight: '30px',
  144 +});
  145 +
  146 +interface Value {
  147 + value?: string;
  148 + label?: string;
  149 +}
  150 +const props = defineProps({
  151 + initialData: {
  152 + type: Object,
  153 + default: () => ({
  154 + form: {
  155 + recordCode: '',
  156 + preserveName: '',
  157 + preservePlanId: '',
  158 + preserveDate: '',
  159 + preserveStatus: '',
  160 + orgId: '',
  161 + preserveBy: '',
  162 + preserveByName: '',
  163 + },
  164 + tableData: [],
  165 + }),
  166 + },
  167 + visible: {
  168 + type: Boolean,
  169 + default: false,
  170 + },
  171 + isViewMode: {
  172 + type: Boolean,
  173 + default: false,
  174 + },
  175 + modalTitle: {
  176 + type: String,
  177 + default: '',
  178 + },
  179 +});
  180 +const visible = ref(props.visible);
  181 +const isViewMode = ref(props.isViewMode);
  182 +const modalTitle = ref(props.modalTitle);
  183 +const defaultOptions = [
  184 + {
  185 + label: '未执行',
  186 + value: 'UNEXECUTED',
  187 + },
  188 + {
  189 + label: '已执行',
  190 + value: 'EXECUTED',
  191 + },
  192 +]
  193 +const form = ref({ ...props.initialData.form });
  194 +const tableData = ref([...props.initialData.tableData]);
  195 +const emit = defineEmits(['update:visible', 'submit']);
  196 +const planOptions = ref([]);
  197 +const Options = ref([]);
  198 +const rules = {
  199 + recordCode: [
  200 + { required: true, message: '请输入', trigger: 'blur' },
  201 + ],
  202 + preservePlanId: [{ required: true, message: '请选择', trigger: 'change' }],
  203 + orgId: [{ required: true, message: '请选择', trigger: 'change' }],
  204 + preserveBy: [{ required: true, message: '请选择', trigger: 'change' }],
  205 + preserveByName: [{ required: true, message: '请选择', trigger: 'change' }],
  206 + preserveStatus: [{ required: true, message: '请选择', trigger: 'change' }],
  207 +};
  208 +
  209 +const columns = [
  210 + {
  211 + title: '保养明细编号',
  212 + dataIndex: 'detailCode',
  213 + slots: { customRender: 'detailCode' },
  214 + width: '160px'
  215 + },
  216 + {
  217 + title: '保养设备',
  218 + dataIndex: 'deviceInfo',
  219 + slots: { customRender: 'deviceInfo' },
  220 + width: '180px'
  221 + },
  222 + {
  223 + title: '保养明细',
  224 + dataIndex: 'preserveDetail',
  225 + width: '180px'
  226 + },
  227 + {
  228 + title: '执行状态',
  229 + dataIndex: 'status',
  230 + slots: { customRender: 'status' },
  231 + width: '160px'
  232 + },
  233 + {
  234 + title: '操作',
  235 + dataIndex: 'operation',
  236 + slots: { customRender: 'operation' },
  237 + width: '120px'
  238 + }
  239 +];
  240 +
  241 +
  242 +const userInfo = useUserStore();
  243 +const timespan = ref(Date.now());
  244 +const orgList = ref<Recordable[]>([]);
  245 +const { t } = useI18n();
  246 +const needReload = ref(true);
  247 +const getBindProps = computed<Recordable>(() => {
  248 + const params = {}
  249 + return {
  250 + replaceFields: { children: 'children', key: 'id', title: 'name', value: 'id' },
  251 + getPopupContainer: () => document.body,
  252 + placeholder: t('deviceManagement.device.organizationPlaceholderText'),
  253 + maxLength: 250,
  254 + value: form.orgId,
  255 + dropdownStyle: { maxHeight: '300px' },
  256 + api: async (params: OrganizationListItem) => {
  257 + try {
  258 + const result = ((await getOrganizationList(params)) as unknown as Recordable[]) || [];
  259 + orgList.value = result;
  260 + needReload.value = false;
  261 + return result;
  262 + } catch (error) {
  263 + return unref(orgList);
  264 + }
  265 + },
  266 + params: {
  267 + ...params,
  268 + _t: unref(timespan),
  269 + },
  270 + onChange: async (...args: any[]) => {
  271 + const _data = {
  272 + page: '1',
  273 + pageSize: '999',
  274 + tenantId: userInfo.getUserInfo.tenantId!,
  275 + organizationId: args?.[0]
  276 + }
  277 + const response = await getUserListByOrg(_data); // 调用接口
  278 + Options.value = response.items?.map((item: any) => {
  279 + return {
  280 + label: item.username,
  281 + value: item.id,
  282 + }
  283 + });
  284 + form.orgId.value = args?.[0]
  285 +
  286 + },
  287 + };
  288 +});
  289 +
  290 +
  291 +// 监听 initialData 的变化
  292 +watch(
  293 + () => props.initialData,
  294 + (newVal) => {
  295 + form.value = { ...newVal.form };
  296 + tableData.value = [...newVal.tableData];
  297 + },
  298 + { deep: true }
  299 +);
  300 +
  301 +
  302 +const handleDelete = (index) => {
  303 + tableData.value.splice(index, 1);
  304 +};
  305 +
  306 +const handleChange = async (value: Value) => {
  307 + const res = await serveRecordDetail({preservePlanId:value,page:'1',pageSize:'999'})
  308 + tableData.value = res?.items?.map((item: any) => {
  309 + return {
  310 + detailCode: item?.detailCode || '',
  311 + preserveDetail: item?.preserveDetail || '',
  312 + deviceInfo: item?.deviceInfo || {},
  313 + preserveDetailId: item?.id || '',
  314 + status: 'UNEXECUTED'
  315 + }
  316 + }) || []
  317 +};
  318 +
  319 +// 监听 visible 的变化
  320 +watch(
  321 + () => props.visible,
  322 + (newVal) => {
  323 + visible.value = newVal;
  324 + }
  325 +);
  326 +
  327 +watch(
  328 + () => props.isViewMode,
  329 + (newVal) => {
  330 + isViewMode.value = newVal;
  331 + }
  332 +);
  333 +
  334 +// 监听 visible 的变化并通知父组件
  335 +watch(
  336 + () => visible.value,
  337 + (newVal) => {
  338 + emit('update:visible', newVal);
  339 + }
  340 +);
  341 +
  342 +onMounted(() => {
  343 + fetchAgeOptions();
  344 +});
  345 +
  346 +const fetchAgeOptions = async () => {
  347 + try {
  348 + const response = await getServicePlanList({ page: 1, pageSize: 999 }); // 调用接口
  349 + planOptions.value = response.items?.map((item: any) => {
  350 + return {
  351 + value: item?.id,
  352 + label: item?.preserveName
  353 + }
  354 + });
  355 + } catch (error) {
  356 + console.error('失败:', error);
  357 + }
  358 +};
  359 +
  360 +const handleOk = () => {
  361 + if (isViewMode.value) {
  362 + visible.value = false;
  363 + return;
  364 + }
  365 + const objData = { ...form.value, preserveDetailStatusList: tableData.value };
  366 + emit('submit', objData); // 将数据提交给父组件
  367 + resetForm();
  368 +}
  369 +const handleCancel = () => {
  370 + resetForm();
  371 + visible.value = false;
  372 +}
  373 +
  374 +// 清空表单和表格数据
  375 +const resetForm = () => {
  376 + form.value = {
  377 + recordCode: '',
  378 + preserveName: '',
  379 + preservePlanId: '',
  380 + preserveDate: '',
  381 + preserveStatus: '',
  382 + orgId: '',
  383 + preserveBy: '',
  384 + preserveByName: '',
  385 + };
  386 + tableData.value = [];
  387 + isViewMode.value = false;
  388 +};
  389 +
  390 +const goChoose = () => {
  391 + userVisible.value = true;
  392 + selectedItem.value = null;
  393 +}
  394 +
  395 +const handleSelect = async (organizationId: string) => {
  396 + searchInfo.organizationId = organizationId;
  397 + const _data = {
  398 + page: '1',
  399 + pageSize: '999',
  400 + tenantId: userInfo.getUserInfo.tenantId!,
  401 + organizationId: organizationId
  402 + }
  403 + const response = await getUserListByOrg(_data); // 调用接口
  404 + Options.value = response.items;
  405 +
  406 +};
  407 +
  408 +// 确认按钮的回调
  409 +const handleUserOk = () => {
  410 + if (!selectedItem.value) {
  411 + createMessage.warning('请选择一个用户');
  412 + return;
  413 + }
  414 + form.value.preserveBy = selectedItem.value.id
  415 + form.value.preserveByName = selectedItem.value.username
  416 +
  417 + userVisible.value = false; // 关闭弹框
  418 +};
  419 +
  420 +const handleUserCancel = () => {
  421 + selectedItem.value = null;
  422 + userVisible.value = false;
  423 +};
  424 +</script>
  425 +
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <BasicTable :clickToRowSelect="false" @register="registerTable"> 3 <BasicTable :clickToRowSelect="false" @register="registerTable">
4 <template #toolbar> 4 <template #toolbar>
5 <Authority value="api:yt:product:category:post"> 5 <Authority value="api:yt:product:category:post">
6 - <Button type="primary" > 6 + <Button type="primary" @click="handleCreate">
7 {{ t('inspection.serviceRecord.createCategoryText') }} 7 {{ t('inspection.serviceRecord.createCategoryText') }}
8 </Button> 8 </Button>
9 </Authority> 9 </Authority>
@@ -24,10 +24,16 @@ @@ -24,10 +24,16 @@
24 <TableAction 24 <TableAction
25 :actions="[ 25 :actions="[
26 { 26 {
  27 + label: t('common.viewText'),
  28 + auth: 'api:yt:product:category:update',
  29 + icon: 'ant-design:eye-outlined',
  30 + onClick: handleViewDetail.bind(null, record),
  31 + },
  32 + {
27 label: t('common.editText'), 33 label: t('common.editText'),
28 auth: 'api:yt:product:category:update', 34 auth: 'api:yt:product:category:update',
29 icon: 'clarity:note-edit-line', 35 icon: 'clarity:note-edit-line',
30 - // onClick: handleEdit.bind(null, record), 36 + onClick: handleEdit.bind(null, record),
31 }, 37 },
32 { 38 {
33 label: t('common.delText'), 39 label: t('common.delText'),
@@ -43,17 +49,46 @@ @@ -43,17 +49,46 @@
43 /> 49 />
44 </template> 50 </template>
45 </BasicTable> 51 </BasicTable>
  52 + <serviceRecordModal
  53 + v-model:visible="modalVisible"
  54 + :initial-data="initialData"
  55 + :is-view-mode="isViewMode"
  56 + :title="modalTitle"
  57 + @submit="handleSubmit"
  58 + />
46 </div> 59 </div>
47 </template> 60 </template>
48 <script setup lang="ts"> 61 <script setup lang="ts">
49 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 62 import { BasicTable, useTable, TableAction } from '/@/components/Table';
50 -import { getServiceRecordList, deleteServeRecord } from '/@/api/inspection/serviceRecord'; 63 +import {
  64 + getServiceRecordList,
  65 + deleteServeRecord,
  66 + savePreserveRecord, getRecordDetail
  67 +} from '/@/api/inspection/serviceRecord';
51 import { columns, searchFormSchema } from './index'; 68 import { columns, searchFormSchema } from './index';
52 import { useI18n } from '/@/hooks/web/useI18n'; 69 import { useI18n } from '/@/hooks/web/useI18n';
53 -import { Button, Tag } from 'ant-design-vue'; 70 +import {Button, message, Tag} from 'ant-design-vue';
54 import {useMessage} from "/@/hooks/web/useMessage"; 71 import {useMessage} from "/@/hooks/web/useMessage";
  72 +import { serviceRecordModal } from "./components/index"
  73 +import {ref} from "vue";
55 const { t } = useI18n(); 74 const { t } = useI18n();
56 const { createMessage } = useMessage(); 75 const { createMessage } = useMessage();
  76 +const modalVisible = ref(false);
  77 +const isViewMode = ref(false);
  78 +const modalTitle = ref('');
  79 +import { dateFormat } from '/@/utils/common/compUtils';
  80 +const initialData = ref({
  81 + form: {
  82 + recordCode: '',
  83 + preservePlanId: '',
  84 + preserveStatus: '',
  85 + preserveBy: '',
  86 + preserveByName: '',
  87 + preserveDate: '',
  88 + orgId: '',
  89 + },
  90 + tableData: [],
  91 +});
57 92
58 const [ 93 const [
59 registerTable, 94 registerTable,
@@ -104,4 +139,69 @@ const handleReload = () => { @@ -104,4 +139,69 @@ const handleReload = () => {
104 reload(); 139 reload();
105 }; 140 };
106 141
  142 +const handleCreate = () => {
  143 + modalTitle.value = '新增';
  144 + initialData.value = {
  145 + form: {
  146 + recordCode: '',
  147 + preservePlanId: '',
  148 + preserveStatus: '',
  149 + preserveBy: '',
  150 + preserveByName: '',
  151 + preserveDate: '',
  152 + orgId: '',
  153 + },
  154 + tableData: [],
  155 + }
  156 + modalVisible.value = true;
  157 +}
  158 +
  159 +const handleSubmit = async (data) => {
  160 + const format = 'yyyy-MM-dd hh:mm:ss';
  161 + modalVisible.value = false;
  162 + const _data = {
  163 + ...data,
  164 + preserveDate: dateFormat(data?.preserveDate, format)
  165 + }
  166 + await savePreserveRecord(_data)
  167 + message.success('提交成功');
  168 + handleReload()
  169 +};
  170 +
  171 +const handleEdit = async (record?: any) => {
  172 + let id = record.id;
  173 + modalTitle.value = '修改';
  174 + try {
  175 + const response = await getRecordDetail({id})
  176 + console.log(response,'res')
  177 + initialData.value = {
  178 + form: response, // 表单数据
  179 + tableData: response.preserveDetailStatusList, // 表格数据
  180 + };
  181 + modalVisible.value = true; // 打开弹框
  182 + }catch (error) {
  183 + throw error;
  184 + }finally {
  185 +
  186 + }
  187 +}
  188 +
  189 +const handleViewDetail = async (record?: any) => {
  190 + let id = record.id;
  191 + modalTitle.value = '查看';
  192 + try {
  193 + const response = await getRecordDetail({id})
  194 + initialData.value = {
  195 + form: response, // 表单数据
  196 + tableData: response.preserveDetailStatusList, // 表格数据
  197 + };
  198 + modalVisible.value = true; // 打开弹框
  199 + isViewMode.value = true;
  200 + }catch (error) {
  201 + throw error;
  202 + }finally {
  203 +
  204 + }
  205 +}
  206 +
107 </script> 207 </script>