1	<template>
2	  <div class="page-container">
3	    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '故障报修' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
4	      <template #toolbar-actions>
5	        <a-button v-permission="'biz:failure:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增故障</a-button>
6	      </template>
7	      <template #bodyCell="{ column, record }">
8	        <template v-if="column.key === 'status'">
9	          <a-tag :color="record.status === 'open' ? 'red' : record.status === 'in_progress' ? 'orange' : record.status === 'resolved' ? 'blue' : 'green'">{{ record.status === 'open' ? '待处理' : record.status === 'in_progress' ? '处理中' : record.status === 'resolved' ? '已修复' : '已关闭' }}</a-tag>
10	        </template>
11	        <template v-if="column.key === 'operations'">
12	          <a-space :size="4" @click.stop>
13	            <a-button v-permission="'biz:failure:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
14	            <a-popconfirm v-permission="'biz:failure:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
15	              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
16	            </a-popconfirm>
17	          </a-space>
18	        </template>
19	      </template>
20	    </ProTable>
21
22	    <a-modal v-model:open="visible" :title="isEdit ? '编辑故障' : '新增故障'" @ok="handleSubmit" width="700px">
23	      <a-form :model="form" :label-col="{ span: 6 }">
24	        <a-row :gutter="16">
25	          <a-col :span="12"><a-form-item label="故障名称" required><a-input v-model:value="form.failure_name" /></a-form-item></a-col>
26	          <a-col :span="12"><a-form-item label="关联类型"><a-input v-model:value="form.target_type" placeholder="device/license/accessory" /></a-form-item></a-col>
27	          <a-col :span="12"><a-form-item label="关联资产ID"><a-input v-model:value="form.target_id" /></a-form-item></a-col>
28	          <a-col :span="12"><a-form-item label="故障日期" required><a-input v-model:value="form.failure_date" type="date" /></a-form-item></a-col>
29	          <a-col :span="12"><a-form-item label="状态">
30	            <a-select v-model:value="form.status">
31	              <a-select-option value="open">待处理</a-select-option>
32	              <a-select-option value="in_progress">处理中</a-select-option>
33	              <a-select-option value="resolved">已修复</a-select-option>
34	              <a-select-option value="closed">已关闭</a-select-option>
35	            </a-select>
36	          </a-form-item></a-col>
37	          <a-col :span="12"><a-form-item label="报告人ID"><a-input v-model:value="form.reported_by" /></a-form-item></a-col>
38	          <a-col :span="12"><a-form-item label="解决人ID"><a-input v-model:value="form.resolved_by" /></a-form-item></a-col>
39	          <a-col :span="24"><a-form-item label="故障描述" :label-col="{ span: 3 }"><a-textarea v-model:value="form.failure_description" :rows="3" /></a-form-item></a-col>
40	          <a-col :span="24"><a-form-item label="备注" :label-col="{ span: 3 }"><a-textarea v-model:value="form.notes" :rows="2" /></a-form-item></a-col>
41	        </a-row>
42	      </a-form>
43	    </a-modal>
44
45	    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
46	      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
47	        <template #bodyCell="{ column, record: row }">
48	          <template v-if="column.key === 'change_type'">
49	            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
50	          </template>
51	        </template>
52	      </a-table>
53	    </a-modal>
54	  </div>
55	</template>
56
57	<script setup lang="ts">
58	import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
59	import { message } from "antdv-next";
60	import { ref } from "vue";
61	import { failureApi, changeRecordApi } from "@/api/asset";
62	import ProTable from "@/components/Pro/ProTable/index.vue";
63	import type { ProTableColumn } from "@/types/pro";
64
65	const tableRef = ref();
66	const visible = ref(false); const isEdit = ref(false);
67	const form = ref<Record<string, unknown>>({});
68
69	const logVisible = ref(false);
70	const logData = ref<Record<string, unknown>[]>([]);
71	const logColumns = [
72	  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
73	  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
74	  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
75	  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
76	  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
77	  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
78	];
79
80	const columns: ProTableColumn[] = [
81	  { title: "故障名称", dataIndex: "failure_name", key: "failure_name", search: true, searchType: "input" },
82	  { title: "关联类型", dataIndex: "target_type", key: "target_type" },
83	  { title: "状态", dataIndex: "status", key: "status" },
84	  { title: "报告人", dataIndex: "reported_user_name", key: "reported_user_name" },
85	  { title: "解决人", dataIndex: "resolved_user_name", key: "resolved_user_name" },
86	  { title: "故障日期", dataIndex: "failure_date", key: "failure_date" },
87	  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
88	];
89
90	const loadData = async (params: Record<string, unknown>) => {
91	  try {
92	    const res: any = await failureApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
93	    const pageData = res.data || res;
94	    return { data: pageData.list || [], total: pageData.total || 0, success: true };
95	  } catch { return { data: [], total: 0, success: false }; }
96	};
97
98	const showChangeLog = async (record: Record<string, unknown>) => {
99	  try {
100	    const res: any = await changeRecordApi.page({ asset_type: "failure", asset_id: record.id, page: 1, pageSize: 200 });
101	    logData.value = (res.data || res).list || [];
102	    logVisible.value = true;
103	  } catch { message.error("获取变更记录失败"); }
104	};
105
106	const handleAdd = () => { isEdit.value = false; form.value = { status: 'open' }; visible.value = true; };
107	const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
108	const handleDelete = async (id: string) => {
109	  await failureApi.del(id);
110	  message.success("删除成功");
111	  tableRef.value?.reload();
112	};
113	const handleSubmit = async () => {
114	  await failureApi.save(form.value);
115	  message.success(isEdit.value ? "更新成功" : "创建成功");
116	  visible.value = false;
117	  tableRef.value?.reload();
118	};
119	</script>
120

<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '故障报修' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'biz:failure:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增故障</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'status'">
          <a-tag :color="record.status === 'open' ? 'red' : record.status === 'in_progress' ? 'orange' : record.status === 'resolved' ? 'blue' : 'green'">{{ record.status === 'open' ? '待处理' : record.status === 'in_progress' ? '处理中' : record.status === 'resolved' ? '已修复' : '已关闭' }}</a-tag>
        </template>
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'biz:failure:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'biz:failure:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑故障' : '新增故障'" @ok="handleSubmit" width="700px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-row :gutter="16">
          <a-col :span="12"><a-form-item label="故障名称" required><a-input v-model:value="form.failure_name" /></a-form-item></a-col>
          <a-col :span="12"><a-form-item label="关联类型"><a-input v-model:value="form.target_type" placeholder="device/license/accessory" /></a-form-item></a-col>
          <a-col :span="12"><a-form-item label="关联资产ID"><a-input v-model:value="form.target_id" /></a-form-item></a-col>
          <a-col :span="12"><a-form-item label="故障日期" required><a-input v-model:value="form.failure_date" type="date" /></a-form-item></a-col>
          <a-col :span="12"><a-form-item label="状态">
            <a-select v-model:value="form.status">
              <a-select-option value="open">待处理</a-select-option>
              <a-select-option value="in_progress">处理中</a-select-option>
              <a-select-option value="resolved">已修复</a-select-option>
              <a-select-option value="closed">已关闭</a-select-option>
            </a-select>
          </a-form-item></a-col>
          <a-col :span="12"><a-form-item label="报告人ID"><a-input v-model:value="form.reported_by" /></a-form-item></a-col>
          <a-col :span="12"><a-form-item label="解决人ID"><a-input v-model:value="form.resolved_by" /></a-form-item></a-col>
          <a-col :span="24"><a-form-item label="故障描述" :label-col="{ span: 3 }"><a-textarea v-model:value="form.failure_description" :rows="3" /></a-form-item></a-col>
          <a-col :span="24"><a-form-item label="备注" :label-col="{ span: 3 }"><a-textarea v-model:value="form.notes" :rows="2" /></a-form-item></a-col>
        </a-row>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { failureApi, changeRecordApi } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "故障名称", dataIndex: "failure_name", key: "failure_name", search: true, searchType: "input" },
  { title: "关联类型", dataIndex: "target_type", key: "target_type" },
  { title: "状态", dataIndex: "status", key: "status" },
  { title: "报告人", dataIndex: "reported_user_name", key: "reported_user_name" },
  { title: "解决人", dataIndex: "resolved_user_name", key: "resolved_user_name" },
  { title: "故障日期", dataIndex: "failure_date", key: "failure_date" },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await failureApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "failure", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = { status: 'open' }; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await failureApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await failureApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>


1	<template>
2	  <div class="page-container">
3	    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产分类' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
4	      <template #toolbar-actions>
5	        <a-button v-permission="'base:category:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增分类</a-button>
6	      </template>
7	      <template #bodyCell="{ column, record }">
8	        <template v-if="column.key === 'category_type'">
9	          <a-tag>{{ record.category_type }}</a-tag>
10	        </template>
11	        <template v-if="column.key === 'operations'">
12	          <a-space :size="4" @click.stop>
13	            <a-button v-permission="'base:category:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
14	            <a-popconfirm v-permission="'base:category:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
15	              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
16	            </a-popconfirm>
17	          </a-space>
18	        </template>
19	      </template>
20	    </ProTable>
21
22	    <a-modal v-model:open="visible" :title="isEdit ? '编辑分类' : '新增分类'" @ok="handleSubmit" width="600px">
23	      <a-form :model="form" :label-col="{ span: 6 }">
24	        <a-form-item label="分类名称" required><a-input v-model:value="form.name" /></a-form-item>
25	        <a-form-item label="分类编码" required><a-input v-model:value="form.code" /></a-form-item>
26	        <a-form-item label="分类大类" required>
27	          <a-select v-model:value="form.category_type">
28	            <a-select-option value="device">设备</a-select-option>
29	            <a-select-option value="license">许可证</a-select-option>
30	            <a-select-option value="accessory">配件</a-select-option>
31	            <a-select-option value="consumable">耗材</a-select-option>
32	            <a-select-option value="service">服务</a-select-option>
33	          </a-select>
34	        </a-form-item>
35	        <a-form-item label="父级分类"><a-input v-model:value="form.parent_id" placeholder="留空为顶级分类" /></a-form-item>
36	      </a-form>
37	    </a-modal>
38
39	    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
40	      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
41	        <template #bodyCell="{ column, record: row }">
42	          <template v-if="column.key === 'change_type'">
43	            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
44	          </template>
45	        </template>
46	      </a-table>
47	    </a-modal>
48	  </div>
49	</template>
50
51	<script setup lang="ts">
52	import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
53	import { message } from "antdv-next";
54	import { ref } from "vue";
55	import { categoryApi, changeRecordApi } from "@/api/asset";
56	import ProTable from "@/components/Pro/ProTable/index.vue";
57	import type { ProTableColumn } from "@/types/pro";
58
59	const tableRef = ref();
60	const visible = ref(false); const isEdit = ref(false);
61	const form = ref<Record<string, unknown>>({});
62
63	const logVisible = ref(false);
64	const logData = ref<Record<string, unknown>[]>([]);
65	const logColumns = [
66	  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
67	  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
68	  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
69	  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
70	  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
71	  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
72	];
73
74	const columns: ProTableColumn[] = [
75	  { title: "分类名称", dataIndex: "name", key: "name", search: true, searchType: "input" },
76	  { title: "分类编码", dataIndex: "code", key: "code" },
77	  { title: "分类大类", dataIndex: "category_type", key: "category_type" },
78	  { title: "父级ID", dataIndex: "parent_id", key: "parent_id", ellipsis: true },
79	  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
80	];
81
82	const loadData = async (params: Record<string, unknown>) => {
83	  try {
84	    const res: any = await categoryApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
85	    const pageData = res.data || res;
86	    return { data: pageData.list || [], total: pageData.total || 0, success: true };
87	  } catch { return { data: [], total: 0, success: false }; }
88	};
89
90	const showChangeLog = async (record: Record<string, unknown>) => {
91	  try {
92	    const res: any = await changeRecordApi.page({ asset_type: "category", asset_id: record.id, page: 1, pageSize: 200 });
93	    logData.value = (res.data || res).list || [];
94	    logVisible.value = true;
95	  } catch { message.error("获取变更记录失败"); }
96	};
97
98	const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
99	const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
100	const handleDelete = async (id: string) => {
101	  await categoryApi.del(id);
102	  message.success("删除成功");
103	  tableRef.value?.reload();
104	};
105	const handleSubmit = async () => {
106	  await categoryApi.save(form.value);
107	  message.success(isEdit.value ? "更新成功" : "创建成功");
108	  visible.value = false;
109	  tableRef.value?.reload();
110	};
111	</script>
112

<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产分类' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'base:category:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增分类</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'category_type'">
          <a-tag>{{ record.category_type }}</a-tag>
        </template>
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'base:category:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'base:category:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑分类' : '新增分类'" @ok="handleSubmit" width="600px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-form-item label="分类名称" required><a-input v-model:value="form.name" /></a-form-item>
        <a-form-item label="分类编码" required><a-input v-model:value="form.code" /></a-form-item>
        <a-form-item label="分类大类" required>
          <a-select v-model:value="form.category_type">
            <a-select-option value="device">设备</a-select-option>
            <a-select-option value="license">许可证</a-select-option>
            <a-select-option value="accessory">配件</a-select-option>
            <a-select-option value="consumable">耗材</a-select-option>
            <a-select-option value="service">服务</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="父级分类"><a-input v-model:value="form.parent_id" placeholder="留空为顶级分类" /></a-form-item>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { categoryApi, changeRecordApi } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "分类名称", dataIndex: "name", key: "name", search: true, searchType: "input" },
  { title: "分类编码", dataIndex: "code", key: "code" },
  { title: "分类大类", dataIndex: "category_type", key: "category_type" },
  { title: "父级ID", dataIndex: "parent_id", key: "parent_id", ellipsis: true },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await categoryApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "category", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await categoryApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await categoryApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>


1	<template>
2	  <div class="page-container">
3	    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产分配' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
4	      <template #toolbar-actions>
5	        <a-button v-permission="'biz:allocation:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增分配</a-button>
6	      </template>
7	      <template #bodyCell="{ column, record }">
8	        <template v-if="column.key === 'status'">
9	          <a-tag :color="record.status === 'active' ? 'green' : record.status === 'returned' ? 'blue' : 'default'">{{ record.status === 'active' ? '使用中' : record.status === 'returned' ? '已归还' : record.status }}</a-tag>
10	        </template>
11	        <template v-if="column.key === 'operations'">
12	          <a-space :size="4" @click.stop>
13	            <a-button v-permission="'biz:allocation:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
14	            <a-popconfirm v-permission="'biz:allocation:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
15	              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
16	            </a-popconfirm>
17	          </a-space>
18	        </template>
19	      </template>
20	    </ProTable>
21
22	    <a-modal v-model:open="visible" :title="isEdit ? '编辑分配' : '新增分配'" @ok="handleSubmit" width="600px">
23	      <a-form :model="form" :label-col="{ span: 6 }">
24	        <a-form-item label="资产类型" required><a-input v-model:value="form.item_type" /></a-form-item>
25	        <a-form-item label="资产ID" required><a-input v-model:value="form.item_id" /></a-form-item>
26	        <a-form-item label="持有人类型"><a-input v-model:value="form.owner_type" placeholder="user/location" /></a-form-item>
27	        <a-form-item label="持有人ID"><a-input v-model:value="form.owner_id" /></a-form-item>
28	        <a-form-item label="数量"><a-input-number v-model:value="form.quantity" :min="1" style="width:100%" /></a-form-item>
29	        <a-form-item label="分配日期" required><a-input v-model:value="form.assign_date" type="date" /></a-form-item>
30	        <a-form-item label="预计归还"><a-input v-model:value="form.expected_return_date" type="date" /></a-form-item>
31	        <a-form-item label="备注"><a-textarea v-model:value="form.note" :rows="2" /></a-form-item>
32	      </a-form>
33	    </a-modal>
34
35	    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
36	      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
37	        <template #bodyCell="{ column, record: row }">
38	          <template v-if="column.key === 'change_type'">
39	            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
40	          </template>
41	        </template>
42	      </a-table>
43	    </a-modal>
44	  </div>
45	</template>
46
47	<script setup lang="ts">
48	import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
49	import { message } from "antdv-next";
50	import { ref } from "vue";
51	import { allocationApi, changeRecordApi } from "@/api/asset";
52	import ProTable from "@/components/Pro/ProTable/index.vue";
53	import type { ProTableColumn } from "@/types/pro";
54
55	const tableRef = ref();
56	const visible = ref(false); const isEdit = ref(false);
57	const form = ref<Record<string, unknown>>({});
58
59	const logVisible = ref(false);
60	const logData = ref<Record<string, unknown>[]>([]);
61	const logColumns = [
62	  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
63	  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
64	  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
65	  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
66	  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
67	  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
68	];
69
70	const columns: ProTableColumn[] = [
71	  { title: "资产类型", dataIndex: "item_type", key: "item_type" },
72	  { title: "持有人", dataIndex: "assignee_name", key: "assignee_name" },
73	  { title: "位置", dataIndex: "location_name", key: "location_name" },
74	  { title: "数量", dataIndex: "quantity", key: "quantity" },
75	  { title: "状态", dataIndex: "status", key: "status" },
76	  { title: "分配日期", dataIndex: "assign_date", key: "assign_date" },
77	  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
78	];
79
80	const loadData = async (params: Record<string, unknown>) => {
81	  try {
82	    const res: any = await allocationApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
83	    const pageData = res.data || res;
84	    return { data: pageData.list || [], total: pageData.total || 0, success: true };
85	  } catch { return { data: [], total: 0, success: false }; }
86	};
87
88	const showChangeLog = async (record: Record<string, unknown>) => {
89	  try {
90	    const res: any = await changeRecordApi.page({ asset_type: "allocation", asset_id: record.id, page: 1, pageSize: 200 });
91	    logData.value = (res.data || res).list || [];
92	    logVisible.value = true;
93	  } catch { message.error("获取变更记录失败"); }
94	};
95
96	const handleAdd = () => { isEdit.value = false; form.value = { quantity: 1, status: 'active' }; visible.value = true; };
97	const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
98	const handleDelete = async (id: string) => {
99	  await allocationApi.del(id);
100	  message.success("删除成功");
101	  tableRef.value?.reload();
102	};
103	const handleSubmit = async () => {
104	  await allocationApi.save(form.value);
105	  message.success(isEdit.value ? "更新成功" : "创建成功");
106	  visible.value = false;
107	  tableRef.value?.reload();
108	};
109	</script>
110

<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产分配' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'biz:allocation:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增分配</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'status'">
          <a-tag :color="record.status === 'active' ? 'green' : record.status === 'returned' ? 'blue' : 'default'">{{ record.status === 'active' ? '使用中' : record.status === 'returned' ? '已归还' : record.status }}</a-tag>
        </template>
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'biz:allocation:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'biz:allocation:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑分配' : '新增分配'" @ok="handleSubmit" width="600px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-form-item label="资产类型" required><a-input v-model:value="form.item_type" /></a-form-item>
        <a-form-item label="资产ID" required><a-input v-model:value="form.item_id" /></a-form-item>
        <a-form-item label="持有人类型"><a-input v-model:value="form.owner_type" placeholder="user/location" /></a-form-item>
        <a-form-item label="持有人ID"><a-input v-model:value="form.owner_id" /></a-form-item>
        <a-form-item label="数量"><a-input-number v-model:value="form.quantity" :min="1" style="width:100%" /></a-form-item>
        <a-form-item label="分配日期" required><a-input v-model:value="form.assign_date" type="date" /></a-form-item>
        <a-form-item label="预计归还"><a-input v-model:value="form.expected_return_date" type="date" /></a-form-item>
        <a-form-item label="备注"><a-textarea v-model:value="form.note" :rows="2" /></a-form-item>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { allocationApi, changeRecordApi } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "资产类型", dataIndex: "item_type", key: "item_type" },
  { title: "持有人", dataIndex: "assignee_name", key: "assignee_name" },
  { title: "位置", dataIndex: "location_name", key: "location_name" },
  { title: "数量", dataIndex: "quantity", key: "quantity" },
  { title: "状态", dataIndex: "status", key: "status" },
  { title: "分配日期", dataIndex: "assign_date", key: "assign_date" },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await allocationApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "allocation", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = { quantity: 1, status: 'active' }; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await allocationApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await allocationApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>


1	<template>
2	  <div class="page-container">
3	    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '型号管理' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
4	      <template #toolbar-actions>
5	        <a-button v-permission="'base:model:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增型号</a-button>
6	      </template>
7	      <template #bodyCell="{ column, record }">
8	        <template v-if="column.key === 'operations'">
9	          <a-space :size="4" @click.stop>
10	            <a-button v-permission="'base:model:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
11	            <a-popconfirm v-permission="'base:model:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
12	              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
13	            </a-popconfirm>
14	          </a-space>
15	        </template>
16	      </template>
17	    </ProTable>
18
19	    <a-modal v-model:open="visible" :title="isEdit ? '编辑型号' : '新增型号'" @ok="handleSubmit" width="600px">
20	      <a-form :model="form" :label-col="{ span: 6 }">
21	        <a-form-item label="型号名称" required><a-input v-model:value="form.name" /></a-form-item>
22	        <a-form-item label="型号编号"><a-input v-model:value="form.model_number" /></a-form-item>
23	        <a-form-item label="制造商ID"><a-input v-model:value="form.manufacturer_id" /></a-form-item>
24	        <a-form-item label="分类ID"><a-input v-model:value="form.category_id" /></a-form-item>
25	      </a-form>
26	    </a-modal>
27
28	    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
29	      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
30	        <template #bodyCell="{ column, record: row }">
31	          <template v-if="column.key === 'change_type'">
32	            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
33	          </template>
34	        </template>
35	      </a-table>
36	    </a-modal>
37	  </div>
38	</template>
39
40	<script setup lang="ts">
41	import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
42	import { message } from "antdv-next";
43	import { ref } from "vue";
44	import { modelApi, changeRecordApi } from "@/api/asset";
45	import ProTable from "@/components/Pro/ProTable/index.vue";
46	import type { ProTableColumn } from "@/types/pro";
47
48	const tableRef = ref();
49	const visible = ref(false); const isEdit = ref(false);
50	const form = ref<Record<string, unknown>>({});
51
52	const logVisible = ref(false);
53	const logData = ref<Record<string, unknown>[]>([]);
54	const logColumns = [
55	  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
56	  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
57	  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
58	  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
59	  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
60	  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
61	];
62
63	const columns: ProTableColumn[] = [
64	  { title: "型号名称", dataIndex: "name", key: "name", search: true, searchType: "input" },
65	  { title: "型号编号", dataIndex: "model_number", key: "model_number" },
66	  { title: "制造商", dataIndex: "manufacturer_name", key: "manufacturer_name" },
67	  { title: "分类", dataIndex: "category_name", key: "category_name" },
68	  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
69	];
70
71	const loadData = async (params: Record<string, unknown>) => {
72	  try {
73	    const res: any = await modelApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
74	    const pageData = res.data || res;
75	    return { data: pageData.list || [], total: pageData.total || 0, success: true };
76	  } catch { return { data: [], total: 0, success: false }; }
77	};
78
79	const showChangeLog = async (record: Record<string, unknown>) => {
80	  try {
81	    const res: any = await changeRecordApi.page({ asset_type: "model", asset_id: record.id, page: 1, pageSize: 200 });
82	    logData.value = (res.data || res).list || [];
83	    logVisible.value = true;
84	  } catch { message.error("获取变更记录失败"); }
85	};
86
87	const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
88	const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
89	const handleDelete = async (id: string) => {
90	  await modelApi.del(id);
91	  message.success("删除成功");
92	  tableRef.value?.reload();
93	};
94	const handleSubmit = async () => {
95	  await modelApi.save(form.value);
96	  message.success(isEdit.value ? "更新成功" : "创建成功");
97	  visible.value = false;
98	  tableRef.value?.reload();
99	};
100	</script>
101

<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '型号管理' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'base:model:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增型号</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'base:model:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'base:model:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑型号' : '新增型号'" @ok="handleSubmit" width="600px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-form-item label="型号名称" required><a-input v-model:value="form.name" /></a-form-item>
        <a-form-item label="型号编号"><a-input v-model:value="form.model_number" /></a-form-item>
        <a-form-item label="制造商ID"><a-input v-model:value="form.manufacturer_id" /></a-form-item>
        <a-form-item label="分类ID"><a-input v-model:value="form.category_id" /></a-form-item>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { modelApi, changeRecordApi } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "型号名称", dataIndex: "name", key: "name", search: true, searchType: "input" },
  { title: "型号编号", dataIndex: "model_number", key: "model_number" },
  { title: "制造商", dataIndex: "manufacturer_name", key: "manufacturer_name" },
  { title: "分类", dataIndex: "category_name", key: "category_name" },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await modelApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "model", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await modelApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await modelApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>


1	<template>
2	  <div class="page-container">
3	    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产申请' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
4	      <template #toolbar-actions>
5	        <a-button v-permission="'biz:request:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增申请</a-button>
6	      </template>
7	      <template #bodyCell="{ column, record }">
8	        <template v-if="column.key === 'status'">
9	          <a-tag :color="record.status === 'pending' ? 'orange' : record.status === 'approved' ? 'green' : record.status === 'rejected' ? 'red' : 'default'">{{ record.status === 'pending' ? '待审批' : record.status === 'approved' ? '已批准' : record.status === 'rejected' ? '已拒绝' : '已取消' }}</a-tag>
10	        </template>
11	        <template v-if="column.key === 'operations'">
12	          <a-space :size="4" @click.stop>
13	            <a-button v-permission="'biz:request:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
14	            <a-popconfirm v-permission="'biz:request:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
15	              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
16	            </a-popconfirm>
17	          </a-space>
18	        </template>
19	      </template>
20	    </ProTable>
21
22	    <a-modal v-model:open="visible" :title="isEdit ? '编辑申请' : '新增申请'" @ok="handleSubmit" width="600px">
23	      <a-form :model="form" :label-col="{ span: 6 }">
24	        <a-form-item label="申请单号"><a-input v-model:value="form.request_no" disabled /></a-form-item>
25	        <a-form-item label="申请人ID"><a-input v-model:value="form.user_id" /></a-form-item>
26	        <a-form-item label="资产类型"><a-input v-model:value="form.item_type" /></a-form-item>
27	        <a-form-item label="分类ID"><a-input v-model:value="form.category_id" /></a-form-item>
28	        <a-form-item label="数量"><a-input-number v-model:value="form.quantity" :min="1" style="width:100%" /></a-form-item>
29	        <a-form-item label="申请原因"><a-textarea v-model:value="form.reason" :rows="2" /></a-form-item>
30	        <a-form-item label="状态">
31	          <a-select v-model:value="form.status">
32	            <a-select-option value="pending">待审批</a-select-option>
33	            <a-select-option value="approved">已批准</a-select-option>
34	            <a-select-option value="rejected">已拒绝</a-select-option>
35	            <a-select-option value="cancelled">已取消</a-select-option>
36	          </a-select>
37	        </a-form-item>
38	      </a-form>
39	    </a-modal>
40
41	    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
42	      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
43	        <template #bodyCell="{ column, record: row }">
44	          <template v-if="column.key === 'change_type'">
45	            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
46	          </template>
47	        </template>
48	      </a-table>
49	    </a-modal>
50	  </div>
51	</template>
52
53	<script setup lang="ts">
54	import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
55	import { message } from "antdv-next";
56	import { ref } from "vue";
57	import { requestApi, changeRecordApi } from "@/api/asset";
58	import ProTable from "@/components/Pro/ProTable/index.vue";
59	import type { ProTableColumn } from "@/types/pro";
60
61	const tableRef = ref();
62	const visible = ref(false); const isEdit = ref(false);
63	const form = ref<Record<string, unknown>>({});
64
65	const logVisible = ref(false);
66	const logData = ref<Record<string, unknown>[]>([]);
67	const logColumns = [
68	  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
69	  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
70	  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
71	  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
72	  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
73	  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
74	];
75
76	const columns: ProTableColumn[] = [
77	  { title: "申请单号", dataIndex: "request_no", key: "request_no", search: true, searchType: "input" },
78	  { title: "申请人", dataIndex: "user_name", key: "user_name" },
79	  { title: "资产类型", dataIndex: "item_type", key: "item_type" },
80	  { title: "分类", dataIndex: "category_name", key: "category_name" },
81	  { title: "数量", dataIndex: "quantity", key: "quantity" },
82	  { title: "状态", dataIndex: "status", key: "status" },
83	  { title: "审批人", dataIndex: "approver_name", key: "approver_name" },
84	  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
85	];
86
87	const loadData = async (params: Record<string, unknown>) => {
88	  try {
89	    const res: any = await requestApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
90	    const pageData = res.data || res;
91	    return { data: pageData.list || [], total: pageData.total || 0, success: true };
92	  } catch { return { data: [], total: 0, success: false }; }
93	};
94
95	const showChangeLog = async (record: Record<string, unknown>) => {
96	  try {
97	    const res: any = await changeRecordApi.page({ asset_type: "asset_request", asset_id: record.id, page: 1, pageSize: 200 });
98	    logData.value = (res.data || res).list || [];
99	    logVisible.value = true;
100	  } catch { message.error("获取变更记录失败"); }
101	};
102
103	const handleAdd = () => { isEdit.value = false; form.value = { quantity: 1, status: 'pending' }; visible.value = true; };
104	const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
105	const handleDelete = async (id: string) => {
106	  await requestApi.del(id);
107	  message.success("删除成功");
108	  tableRef.value?.reload();
109	};
110	const handleSubmit = async () => {
111	  await requestApi.save(form.value);
112	  message.success(isEdit.value ? "更新成功" : "创建成功");
113	  visible.value = false;
114	  tableRef.value?.reload();
115	};
116	</script>
117

<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产申请' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'biz:request:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增申请</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'status'">
          <a-tag :color="record.status === 'pending' ? 'orange' : record.status === 'approved' ? 'green' : record.status === 'rejected' ? 'red' : 'default'">{{ record.status === 'pending' ? '待审批' : record.status === 'approved' ? '已批准' : record.status === 'rejected' ? '已拒绝' : '已取消' }}</a-tag>
        </template>
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'biz:request:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'biz:request:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑申请' : '新增申请'" @ok="handleSubmit" width="600px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-form-item label="申请单号"><a-input v-model:value="form.request_no" disabled /></a-form-item>
        <a-form-item label="申请人ID"><a-input v-model:value="form.user_id" /></a-form-item>
        <a-form-item label="资产类型"><a-input v-model:value="form.item_type" /></a-form-item>
        <a-form-item label="分类ID"><a-input v-model:value="form.category_id" /></a-form-item>
        <a-form-item label="数量"><a-input-number v-model:value="form.quantity" :min="1" style="width:100%" /></a-form-item>
        <a-form-item label="申请原因"><a-textarea v-model:value="form.reason" :rows="2" /></a-form-item>
        <a-form-item label="状态">
          <a-select v-model:value="form.status">
            <a-select-option value="pending">待审批</a-select-option>
            <a-select-option value="approved">已批准</a-select-option>
            <a-select-option value="rejected">已拒绝</a-select-option>
            <a-select-option value="cancelled">已取消</a-select-option>
          </a-select>
        </a-form-item>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { requestApi, changeRecordApi } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "申请单号", dataIndex: "request_no", key: "request_no", search: true, searchType: "input" },
  { title: "申请人", dataIndex: "user_name", key: "user_name" },
  { title: "资产类型", dataIndex: "item_type", key: "item_type" },
  { title: "分类", dataIndex: "category_name", key: "category_name" },
  { title: "数量", dataIndex: "quantity", key: "quantity" },
  { title: "状态", dataIndex: "status", key: "status" },
  { title: "审批人", dataIndex: "approver_name", key: "approver_name" },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await requestApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "asset_request", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = { quantity: 1, status: 'pending' }; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await requestApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await requestApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>


设备管理-编辑页面，我不需要ID，而是需要实际内容 比如型号、位置什么的


Now I have all 6 files. Let me plan the edits for each:

### 1. category/index.vue
- `parent_id` → category select (self-referencing)
- Need to import `getCategoryList`
- Add categoryOptions ref and loadOptions
- Change `parent_id` input to select

### 2. model/index.vue
- `manufacturer_id` → manufacturer select
- `category_id` → category select
- Need to import `getCategoryList, getManufacturerList`
- Add options refs and loadOptions

### 3. failure/index.vue
- `target_id` → asset select (this is tricky - it references ANY asset type)
- `reported_by` → user select
- `resolved_by` → user select
- For `target_id`, we need a combined list of all assets. But we don't have a single "all assets" API. We could either:
  a. Load all device, license, accessory separately and combine them
  b. Leave target_id as input since it depends on target_type
- Actually, `target_type` is also an input. These two are related - target_type determines which table target_id references. This is complex. Let me keep target_id as input for now (it's a cross-table reference that depends on target_type).
- For `reported_by` and `resolved_by`, use getUserList
- Also `target_type` should be a select (device/license/accessory/consumable) - let me convert that too

### 4. stocktake/index.vue
- `manager_id` → user select (getUserList)
- `location_id` → location select (getLocationList)
- `category_id` → category select (getCategoryList)

### 5. allocation/index.vue
- `item_id` → tricky, references asset by item_type. Similar to failure, depends on item_type. Keep as input.
- `owner_id` → tricky, depends on owner_type (user/location). Keep as input for now.
- `item_type` → should be a select

### 6. request/index.vue
- `user_id` → user select (getUserList)
- `category_id` → category select (getCategoryList)

Let me be pragmatic. For fields that have simple foreign key relationships to a single table (users, categories, manufacturers, locations), I'll convert to selects. For cross-table polymorphic references (target_id + target_type, item_id + item_type, owner_id + owner_type), I'll keep as inputs since they depend on an accompanying type selector.

Let me now make all the edits. I'll process them in parallel where possible.

Actually, let me reconsider allocation:
- `item_type` has possible values like "device", "license", "accessory" - should be a select
- `owner_type` has values like "user", "location" - should be a select
- `item_id` and `owner_id` depend on these types so keep as inputs

And for failure:
- `target_type` has values like "device", "license", "accessory" - should be a select
- `target_id` depends on target_type so keep as input

Let me now make the edits. I'll be strategic - change all the simple foreign key fields and the constrained type fields to selects.


现在并行处理这6个文件。先处理较简单的 category, model, stocktake, request，再处理 failure（需要改造 target_type）和 allocation（需要改造 item_type, owner_type）。


Edit

<a-form-item label="父级分类"><a-input v-model:value="form.parent_id" placeholder="留空为顶级分类" /></a-form-item>

        <a-form-item label="父级分类">
          <a-select v-model:value="form.parent_id" show-search placeholder="留空为顶级分类" option-filter-prop="label" :options="parentOptions" allow-clear />
        </a-form-item>


The file c:\Workspace\Project\tansci\antdv-next-admin\src\views\asset\base\category\index.vue has been updated successfully. (file state is current in your context — no need to Read it back)

        <a-form-item label="父级分类">
          <a-select v-model:value="form.parent_id" show-search placeholder="留空为顶级分类" option-filter-prop="label" :options="parentOptions" allow-clear />
        </a-form-item>

<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产分类' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'base:category:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增分类</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'category_type'">
          <a-tag>{{ record.category_type }}</a-tag>
        </template>
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'base:category:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'base:category:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑分类' : '新增分类'" @ok="handleSubmit" width="600px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-form-item label="分类名称" required><a-input v-model:value="form.name" /></a-form-item>
        <a-form-item label="分类编码" required><a-input v-model:value="form.code" /></a-form-item>
        <a-form-item label="分类大类" required>
          <a-select v-model:value="form.category_type">
            <a-select-option value="device">设备</a-select-option>
            <a-select-option value="license">许可证</a-select-option>
            <a-select-option value="accessory">配件</a-select-option>
            <a-select-option value="consumable">耗材</a-select-option>
            <a-select-option value="service">服务</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="父级分类"><a-input v-model:value="form.parent_id" placeholder="留空为顶级分类" /></a-form-item>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { categoryApi, changeRecordApi } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "分类名称", dataIndex: "name", key: "name", search: true, searchType: "input" },
  { title: "分类编码", dataIndex: "code", key: "code" },
  { title: "分类大类", dataIndex: "category_type", key: "category_type" },
  { title: "父级ID", dataIndex: "parent_id", key: "parent_id", ellipsis: true },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await categoryApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "category", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await categoryApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await categoryApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>

-        <a-form-item label="父级分类"><a-input v-model:value="form.parent_id" placeholder="留空为顶级分类" /></a-form-item>

+          <a-select v-model:value="form.parent_id" show-search placeholder="留空为顶级分类" option-filter-prop="label" :options="parentOptions" allow-clear />


将设备管理编辑表单的ID字段改为下拉选择（型号/分类/位置/供应商/责任人）

修改设备编辑表单为下拉选择

将其他资产页面（license/accessory/consumable）的编辑表单也改为下拉选择


Now let me continue with the other edits. Let me do the script section edits for category, and also the template and script edits for model, stocktake, request, failure, and allocation.

Let me do all independent edits in parallel.


import { categoryApi, changeRecordApi } from "@/api/asset";

import { categoryApi, changeRecordApi, getCategoryList } from "@/api/asset";


<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产分类' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'base:category:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增分类</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'category_type'">
          <a-tag>{{ record.category_type }}</a-tag>
        </template>
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'base:category:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'base:category:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑分类' : '新增分类'" @ok="handleSubmit" width="600px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-form-item label="分类名称" required><a-input v-model:value="form.name" /></a-form-item>
        <a-form-item label="分类编码" required><a-input v-model:value="form.code" /></a-form-item>
        <a-form-item label="分类大类" required>
          <a-select v-model:value="form.category_type">
            <a-select-option value="device">设备</a-select-option>
            <a-select-option value="license">许可证</a-select-option>
            <a-select-option value="accessory">配件</a-select-option>
            <a-select-option value="consumable">耗材</a-select-option>
            <a-select-option value="service">服务</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="父级分类">
          <a-select v-model:value="form.parent_id" show-search placeholder="留空为顶级分类" option-filter-prop="label" :options="parentOptions" allow-clear />
        </a-form-item>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { categoryApi, changeRecordApi } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "分类名称", dataIndex: "name", key: "name", search: true, searchType: "input" },
  { title: "分类编码", dataIndex: "code", key: "code" },
  { title: "分类大类", dataIndex: "category_type", key: "category_type" },
  { title: "父级ID", dataIndex: "parent_id", key: "parent_id", ellipsis: true },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await categoryApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "category", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await categoryApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await categoryApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>

-import { categoryApi, changeRecordApi } from "@/api/asset";

+import { categoryApi, changeRecordApi, getCategoryList } from "@/api/asset";


Let me continue with the edits. I need to add the parentOptions and loadOptions to category, and make handleAdd/handleEdit async.


const form = ref<Record<string, unknown>>({});

const form = ref<Record<string, unknown>>({});

const parentOptions = ref<{ label: string; value: string }[]>([]);

const loadOptions = async () => {
  try {
    const res: any = await getCategoryList();
    const data = (res.data || res) as any[];
    parentOptions.value = (data || []).map((c: any) => ({ label: c.name + ' [' + c.code + ']', value: c.id }));
  } catch { /* ignore */ }
};


const form = ref<Record<string, unknown>>({});

const parentOptions = ref<{ label: string; value: string }[]>([]);

const loadOptions = async () => {
  try {
    const res: any = await getCategoryList();
    const data = (res.data || res) as any[];
    parentOptions.value = (data || []).map((c: any) => ({ label: c.name + ' [' + c.code + ']', value: c.id }));
  } catch { /* ignore */ }
};

<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产分类' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'base:category:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增分类</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'category_type'">
          <a-tag>{{ record.category_type }}</a-tag>
        </template>
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'base:category:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'base:category:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑分类' : '新增分类'" @ok="handleSubmit" width="600px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-form-item label="分类名称" required><a-input v-model:value="form.name" /></a-form-item>
        <a-form-item label="分类编码" required><a-input v-model:value="form.code" /></a-form-item>
        <a-form-item label="分类大类" required>
          <a-select v-model:value="form.category_type">
            <a-select-option value="device">设备</a-select-option>
            <a-select-option value="license">许可证</a-select-option>
            <a-select-option value="accessory">配件</a-select-option>
            <a-select-option value="consumable">耗材</a-select-option>
            <a-select-option value="service">服务</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="父级分类">
          <a-select v-model:value="form.parent_id" show-search placeholder="留空为顶级分类" option-filter-prop="label" :options="parentOptions" allow-clear />
        </a-form-item>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { categoryApi, changeRecordApi, getCategoryList } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "分类名称", dataIndex: "name", key: "name", search: true, searchType: "input" },
  { title: "分类编码", dataIndex: "code", key: "code" },
  { title: "分类大类", dataIndex: "category_type", key: "category_type" },
  { title: "父级ID", dataIndex: "parent_id", key: "parent_id", ellipsis: true },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await categoryApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "category", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await categoryApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await categoryApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>

+const parentOptions = ref<{ label: string; value: string }[]>([]);

+    const res: any = await getCategoryList();

+    const data = (res.data || res) as any[];

+    parentOptions.value = (data || []).map((c: any) => ({ label: c.name + ' [' + c.code + ']', value: c.id }));


Now update handleAdd and handleEdit to be async and call loadOptions.


const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };

const handleAdd = async () => { isEdit.value = false; form.value = {}; await loadOptions(); visible.value = true; };
const handleEdit = async (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; await loadOptions(); visible.value = true; };


const handleAdd = async () => { isEdit.value = false; form.value = {}; await loadOptions(); visible.value = true; };
const handleEdit = async (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; await loadOptions(); visible.value = true; };

<template>
  <div class="page-container">
    <ProTable ref="tableRef" :columns="columns" :request="loadData" :toolbar="{ title: '资产分类' }" :custom-row="(record: any) => ({ onClick: () => showChangeLog(record), style: { cursor: 'pointer' } })">
      <template #toolbar-actions>
        <a-button v-permission="'base:category:add'" type="primary" @click="handleAdd"><PlusOutlined /> 新增分类</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'category_type'">
          <a-tag>{{ record.category_type }}</a-tag>
        </template>
        <template v-if="column.key === 'operations'">
          <a-space :size="4" @click.stop>
            <a-button v-permission="'base:category:edit'" type="link" size="small" @click.stop="handleEdit(record)"><EditOutlined /> 编辑</a-button>
            <a-popconfirm v-permission="'base:category:delete'" title="确认删除？" @confirm="handleDelete(record.id)">
              <a-button type="link" size="small" danger @click.stop><DeleteOutlined /> 删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </ProTable>

    <a-modal v-model:open="visible" :title="isEdit ? '编辑分类' : '新增分类'" @ok="handleSubmit" width="600px">
      <a-form :model="form" :label-col="{ span: 6 }">
        <a-form-item label="分类名称" required><a-input v-model:value="form.name" /></a-form-item>
        <a-form-item label="分类编码" required><a-input v-model:value="form.code" /></a-form-item>
        <a-form-item label="分类大类" required>
          <a-select v-model:value="form.category_type">
            <a-select-option value="device">设备</a-select-option>
            <a-select-option value="license">许可证</a-select-option>
            <a-select-option value="accessory">配件</a-select-option>
            <a-select-option value="consumable">耗材</a-select-option>
            <a-select-option value="service">服务</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="父级分类">
          <a-select v-model:value="form.parent_id" show-search placeholder="留空为顶级分类" option-filter-prop="label" :options="parentOptions" allow-clear />
        </a-form-item>
      </a-form>
    </a-modal>

    <a-modal v-model:open="logVisible" title="变更记录" width="800px" :footer="null">
      <a-table :columns="logColumns" :data-source="logData" :pagination="false" size="small" row-key="id">
        <template #bodyCell="{ column, record: row }">
          <template v-if="column.key === 'change_type'">
            <a-tag :color="row.change_type === 'create' ? 'green' : row.change_type === 'delete' ? 'red' : 'blue'">{{ row.change_type === 'create' ? '新增' : row.change_type === 'delete' ? '删除' : '修改' }}</a-tag>
          </template>
        </template>
      </a-table>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@antdv-next/icons";
import { message } from "antdv-next";
import { ref } from "vue";
import { categoryApi, changeRecordApi, getCategoryList } from "@/api/asset";
import ProTable from "@/components/Pro/ProTable/index.vue";
import type { ProTableColumn } from "@/types/pro";

const tableRef = ref();
const visible = ref(false); const isEdit = ref(false);
const form = ref<Record<string, unknown>>({});

const parentOptions = ref<{ label: string; value: string }[]>([]);

const loadOptions = async () => {
  try {
    const res: any = await getCategoryList();
    const data = (res.data || res) as any[];
    parentOptions.value = (data || []).map((c: any) => ({ label: c.name + ' [' + c.code + ']', value: c.id }));
  } catch { /* ignore */ }
};

const logVisible = ref(false);
const logData = ref<Record<string, unknown>[]>([]);
const logColumns = [
  { title: "时间", dataIndex: "create_time", key: "create_time", width: 170 },
  { title: "变更类型", dataIndex: "change_type", key: "change_type", width: 80 },
  { title: "变更字段", dataIndex: "field_name", key: "field_name", width: 120 },
  { title: "旧值", dataIndex: "old_value", key: "old_value", ellipsis: true },
  { title: "新值", dataIndex: "new_value", key: "new_value", ellipsis: true },
  { title: "操作人", dataIndex: "operator_name", key: "operator_name", width: 100 },
];

const columns: ProTableColumn[] = [
  { title: "分类名称", dataIndex: "name", key: "name", search: true, searchType: "input" },
  { title: "分类编码", dataIndex: "code", key: "code" },
  { title: "分类大类", dataIndex: "category_type", key: "category_type" },
  { title: "父级ID", dataIndex: "parent_id", key: "parent_id", ellipsis: true },
  { title: "操作", dataIndex: "operations", key: "operations", width: 200, fixed: "right" as const },
];

const loadData = async (params: Record<string, unknown>) => {
  try {
    const res: any = await categoryApi.page({ page: params.current, pageSize: params.pageSize, keyword: params.keyword });
    const pageData = res.data || res;
    return { data: pageData.list || [], total: pageData.total || 0, success: true };
  } catch { return { data: [], total: 0, success: false }; }
};

const showChangeLog = async (record: Record<string, unknown>) => {
  try {
    const res: any = await changeRecordApi.page({ asset_type: "category", asset_id: record.id, page: 1, pageSize: 200 });
    logData.value = (res.data || res).list || [];
    logVisible.value = true;
  } catch { message.error("获取变更记录失败"); }
};

const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };
const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };
const handleDelete = async (id: string) => {
  await categoryApi.del(id);
  message.success("删除成功");
  tableRef.value?.reload();
};
const handleSubmit = async () => {
  await categoryApi.save(form.value);
  message.success(isEdit.value ? "更新成功" : "创建成功");
  visible.value = false;
  tableRef.value?.reload();
};
</script>

-const handleAdd = () => { isEdit.value = false; form.value = {}; visible.value = true; };

-const handleEdit = (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; visible.value = true; };

+const handleAdd = async () => { isEdit.value = false; form.value = {}; await loadOptions(); visible.value = true; };

+const handleEdit = async (r: Record<string, unknown>) => { isEdit.value = true; form.value = { ...r }; await loadOptions(); visible.value = true; };


Good, category is done. Now let me do model, failure, stocktake, allocation, request in parallel.

For model: manufacturer_id → select, category_id → select
For failure: reported_by → user select, resolved_by → user select, target_type → select
For stocktake: manager_id → user select, location_id → location select, category_id → category select
For allocation: item_type → select, owner_type → select (keep item_id and owner_id as inputs since they're polymorphic)
For request: user_id → user select, category_id → category select


现在并行处理 model、failure、stocktake、allocation、request 五个文件的模板部分。


        <a-form-item label="制造商ID"><a-input v-model:value="form.manufacturer_id" /></a-form-item>
        <a-form-item label="分类ID"><a-input v-model:value="form.category_id" /></a-form-item>

        <a-form-item label="制造商">
          <a-select v-model:value="form.manufacturer_id" show-search placeholder="请选择制造商" option-filter-prop="label" :options="manufacturerOptions" allow-clear />
        </a-form-item>
        <a-form-item label="分类">
          <a-select v-model:value="form.category_id" show-search placeholder="请选择分类" option-filter-prop="label" :options="categoryOptions" allow-clear />
        </a-form-item>


<a-col :span="12"><a-form-item label="关联类型"><a-input v-model:value="form.target_type" placeholder="device/license/accessory" /></a-form-item></a-col>

          <a-col :span="12"><a-form-item label="关联类型">
            <a-select v-model:value="form.target_type" placeholder="请选择关联类型">
              <a-select-option value="device">设备</a-select-option>
              <a-select-option value="license">许可证</a-select-option>
              <a-select-option value="accessory">配件</a-select-option>
            </a-select>
          </a-form-item></a-col>


          <a-col :span="12"><a-form-item label="报告人ID"><a-input v-model:value="form.reported_by" /></a-form-item></a-col>
          <a-col :span="12"><a-form-item label="解决人ID"><a-input v-model:value="form.resolved_by" /></a-form-item></a-col>

          <a-col :span="12"><a-form-item label="报告人">
            <a-select v-model:value="form.reported_by" show-search placeholder="请选择报告人" option-filter-prop="label" :options="userOptions" allow-clear />
          </a-form-item></a-col>
          <a-col :span="12"><a-form-item label="解决人">
            <a-select v-model:value="form.resolved_by" show-search placeholder="请选择解决人" option-filter-prop="label" :options="userOptions" allow-clear />
          </a-form-item></a-col>


        <a-form-item label="负责人ID"><a-input v-model:value="form.manager_id" /></a-form-item>
        <a-form-item label="位置ID"><a-input v-model:value="form.location_id" /></a-form-item>
        <a-form-item label="分类ID"><a-input v-model:value="form.category_id" /></a-form-item>

        <a-form-item label="负责人">
          <a-select v-model:value="form.manager_id" show-search placeholder="请选择负责人" option-filter-prop="label" :options="userOptions" allow-clear />
        </a-form-item>
        <a-form-item label="位置">
          <a-select v-model:value="form.location_id" show-search placeholder="请选择位置" option-filter-prop="label" :options="locationOptions" allow-clear />
        </a-form-item>
        <a-form-item label="分类">
          <a-select v-model:value="form.category_id" show-search placeholder="请选择分类" option-filter-prop="label" :options="categoryOptions" allow-clear />
        </a-form-item>


<a-form-item label="资产类型" required><a-input v-model:value="form.item_type" /></a-form-item>

        <a-form-item label="资产类型" required>
          <a-select v-model:value="form.item_type" placeholder="请选择资产类型">
            <a-select-option value="device">设备</a-select-option>
            <a-select-option value="license">许可证</a-select-option>
            <a-select-option value="accessory">配件</a-select-option>
          </a-select>
        </a-form-item>


<a-form-item label="持有人类型"><a-input v-model:value="form.owner_type" placeholder="user/location" /></a-form-item>

        <a-form-item label="持有人类型">
          <a-select v-model:value="form.owner_type" placeholder="请选择持有人类型" allow-clear>
            <a-select-option value="user">用户</a-select-option>
            <a-select-option value="location">位置</a-select-option>
          </a-select>
        </a-form-item>


        <a-form-item label="申请人ID"><a-input v-model:value="form.user_id" /></a-form-item>
        <a-form-item label="资产类型"><a-input v-model:value="form.item_type" /></a-form-item>
        <a-form-item label="分类ID"><a-input v-model:value="form.category_id" /></a-form-item>

        <a-form-item label="申请人">
          <a-select v-model:value="form.user_id" show-search placeholder="请选择申请人" option-filter-prop="label" :options="userOptions" allow-clear />
        </a-form-item>
        <a-form-item label="资产类型"><a-input v-model:value="form.item_type" /></a-form-item>
        <a-form-item label="分类">
          <a-select v-model:value="form.category_id" show-search placeholder="请选择分类" option-filter-prop="label" :options="categoryOptions" allow-clear />
        </a-form-item>