index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. <template>
  2. <div class="p-2">
  3. <el-row :gutter="10">
  4. <el-col :span="5">
  5. <el-card>
  6. <template #header>
  7. <div class="card-header">分项系统</div>
  8. </template>
  9. <div>
  10. <el-input v-model="filterText" style="width: 200px" placeholder="请输入关键字" />
  11. <el-tree ref="treeRef" style="max-width: 600px; margin-top: 5px" class="filter-tree" :props="defaultProps"
  12. :data="treeData" node-key="id" default-expand-all highlight-current :expand-on-click-node="false"
  13. :filter-node-method="filterNode" @node-click="handleNodeClick" />
  14. </div>
  15. </el-card>
  16. </el-col>
  17. <el-col :span="19">
  18. <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
  19. :leave-active-class="proxy?.animate.searchAnimate.leave">
  20. <div v-show="showSearch" class="mb-[10px]">
  21. <el-card shadow="hover">
  22. <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
  23. <el-form-item label="设备类型名称" prop="deviceTypeId">
  24. <el-select v-model="queryParams.deviceTypeId" placeholder="请选择设备类型名称">
  25. <el-option v-for="dict in dictGroup.deviceTypeOptions" :key="dict.id" :label="dict.name"
  26. :value="dict.id"></el-option>
  27. </el-select>
  28. </el-form-item>
  29. <el-form-item label="型号" prop="xh">
  30. <el-input v-model="queryParams.xh" placeholder="请输入型号" clearable @keyup.enter="handleQuery" />
  31. </el-form-item>
  32. <el-form-item>
  33. <el-button type="primary" icon="Search" @click="handleQuery"> 搜索 </el-button>
  34. <el-button icon="Refresh" @click="resetQuery"> 重置 </el-button>
  35. </el-form-item>
  36. </el-form>
  37. </el-card>
  38. </div>
  39. </transition>
  40. <el-card shadow="never">
  41. <template #header>
  42. <el-row :gutter="10" class="mb8">
  43. <el-col :span="1.5">
  44. <el-button type="primary" plain icon="Plus" @click="handleAdd"> 新增 </el-button>
  45. </el-col>
  46. <el-col :span="1.5">
  47. <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"> 修改 </el-button>
  48. </el-col>
  49. <el-col :span="1.5">
  50. <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"> 删除 </el-button>
  51. </el-col>
  52. <right-toolbar v-model:showSearch="showSearch" @query-table="getList" />
  53. </el-row>
  54. </template>
  55. <el-table v-loading="loading" :data="deviceTypeList" @selection-change="handleSelectionChange">
  56. <el-table-column type="selection" width="55" align="center" />
  57. <el-table-column label="设备类型名称" width="120" align="center">
  58. <template #default="scope">
  59. {{ formatDict(scope.row.deviceTypeId, 'deviceTypeOptions') }}
  60. </template>
  61. </el-table-column>
  62. <el-table-column label="品牌" align="center" prop="ext1.brand" />
  63. <el-table-column label="型号" align="center" prop="xh" />
  64. <el-table-column label="单位" align="center" prop="units" />
  65. <el-table-column label="供应商" align="center" prop="productorId">
  66. <template #default="scope">
  67. {{ formatDict(scope.row.productorId, 'productorOptions') }}
  68. </template>
  69. </el-table-column>
  70. <el-table-column label="联系人" align="center" prop="ext1.linkName" />
  71. <el-table-column label="联系方式" align="center" prop="ext1.linkPhone" width="120" />
  72. <el-table-column label="备注" align="center" prop="remark" />
  73. <el-table-column label="创建时间" align="center" prop="createTime" width="160" />
  74. <el-table-column label="操作" align="center" width="120" fixed="right" class-name="small-padding fixed-width">
  75. <template #default="scope">
  76. <el-button v-hasPermi="['jdyw:deviceType:edit']" size="small" link type="primary"
  77. @click="handleUpdate(scope.row)">修改</el-button>
  78. <el-button v-hasPermi="['jdyw:deviceType:remove']" size="small" link type="danger"
  79. @click="handleDelete(scope.row)">删除</el-button>
  80. </template>
  81. </el-table-column>
  82. </el-table>
  83. <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
  84. :total="total" @pagination="getList" />
  85. </el-card>
  86. </el-col>
  87. </el-row>
  88. <!-- 添加或修改设备类型信息对话框 -->
  89. <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
  90. <el-form ref="deviceTypeFormRef" :model="form" label-width="110px">
  91. <el-form-item label="设备类型名称" prop="deviceTypeId"
  92. :rules="[{ required: true, message: '设备类型名称不能为空', trigger: 'change' }]">
  93. <el-select v-model="form.deviceTypeId" placeholder="请选择设备类型名称">
  94. <el-option v-for="dict in dictGroup.deviceTypeOptions" :key="dict.id" :label="dict.name"
  95. :value="dict.id"></el-option>
  96. </el-select>
  97. </el-form-item>
  98. <el-form-item label="品牌" prop="ext1.brand" :rules="[{ required: true, message: '品牌不能为空', trigger: 'blur' }]">
  99. <el-input v-model="form.ext1.brand" placeholder="请输入品牌" />
  100. </el-form-item>
  101. <el-form-item label="型号" prop="xh" :rules="[{ required: true, message: '型号不能为空', trigger: 'blur' }]">
  102. <el-input v-model="form.xh" placeholder="请输入型号" />
  103. </el-form-item>
  104. <el-form-item label="单位" prop="units" :rules="[{ required: true, message: '单位不能为空', trigger: 'blur' }]">
  105. <el-input v-model="form.units" placeholder="请输入单位" />
  106. </el-form-item>
  107. <el-form-item label="供应商" prop="productorId"
  108. :rules="[{ required: true, message: '供应商不能为空', trigger: 'change' }]">
  109. <el-select v-model="form.productorId" clearable placeholder="请选择供应商" @change="setProductorInfo">
  110. <el-option v-for="dict in dictGroup.productorOptions" :key="dict.id" :label="dict.name"
  111. :value="dict.id"></el-option>
  112. </el-select>
  113. </el-form-item>
  114. <el-form-item label="供应商联系人" prop="ext1.linkName">
  115. <el-input v-model="form.ext1.linkName" disabled />
  116. </el-form-item>
  117. <el-form-item label="联系电话" prop="ext1.linkPhone">
  118. <el-input v-model="form.ext1.linkPhone" disabled />
  119. </el-form-item>
  120. <el-form-item label="备注" prop="remark">
  121. <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
  122. </el-form-item>
  123. </el-form>
  124. <template #footer>
  125. <div class="dialog-footer">
  126. <el-button :loading="buttonLoading" type="primary" @click="submitForm"> 确 定 </el-button>
  127. <el-button @click="cancel"> 取 消 </el-button>
  128. </div>
  129. </template>
  130. </el-dialog>
  131. </div>
  132. </template>
  133. <script setup name="VersionManage" lang="ts">
  134. import {
  135. listDeviceType,
  136. getDeviceTypeDetail,
  137. delDeviceTypeDetail,
  138. addDeviceTypeDetail,
  139. updateDeviceTypeDetail,
  140. getDeviceSystemTree,
  141. getDeviceTypeDetailList
  142. } from '@/api/deviceManage/deviceType';
  143. import { listProductor } from '@/api/supplierManage/index';
  144. import { deepClone } from '@/utils/index';
  145. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  146. const deviceTypeList = ref([]);
  147. const buttonLoading = ref(false);
  148. const loading = ref(true);
  149. const showSearch = ref(true);
  150. const ids = ref<Array<string | number>>([]);
  151. const single = ref(true);
  152. const multiple = ref(true);
  153. const total = ref(0);
  154. const queryFormRef = ref<ElFormInstance>();
  155. const deviceTypeFormRef = ref<ElFormInstance>();
  156. const filterText = ref('');
  157. const treeRef = ref<ElTreeInstance>();
  158. const filterNode = (value: string, data) => {
  159. if (!value) return true;
  160. return data.name.includes(value);
  161. };
  162. watch(filterText, (val) => {
  163. treeRef.value!.filter(val);
  164. });
  165. const defaultProps = {
  166. children: 'children',
  167. label: 'name'
  168. };
  169. const treeData = ref([]);
  170. const dialog = reactive<DialogOption>({
  171. visible: false,
  172. title: ''
  173. });
  174. const dictGroup = reactive({
  175. deviceTypeOptions: [],
  176. productorOptions: []
  177. });
  178. const initFormData = {
  179. id: undefined,
  180. productorId: '',
  181. deviceTypeId: undefined,
  182. xh: null,
  183. units: undefined,
  184. remark: undefined,
  185. ext1: <any>{
  186. brand: undefined,
  187. linkName: '',
  188. linkPhone: ''
  189. },
  190. ext2: undefined
  191. };
  192. const formData = reactive({
  193. form: { ...initFormData },
  194. queryParams: {
  195. pageNum: 1,
  196. pageSize: 10,
  197. systemId: undefined,
  198. deviceTypeId: undefined,
  199. xh: undefined,
  200. params: {}
  201. }
  202. });
  203. const { queryParams, form } = toRefs(formData);
  204. /** 查询设备类型信息列表 */
  205. const getList = async () => {
  206. loading.value = true;
  207. const res = await getDeviceTypeDetailList(queryParams.value);
  208. deviceTypeList.value = res.rows.map((item) => ({
  209. ...item,
  210. ext1: item.ext1 ? JSON.parse(item.ext1) : null
  211. }));
  212. total.value = res.total;
  213. loading.value = false;
  214. };
  215. /** 取消按钮 */
  216. const cancel = () => {
  217. reset();
  218. dialog.visible = false;
  219. };
  220. /** 表单重置 */
  221. const reset = () => {
  222. form.value = deepClone(initFormData);
  223. deviceTypeFormRef.value?.resetFields();
  224. };
  225. /** 搜索按钮操作 */
  226. const handleQuery = () => {
  227. queryParams.value.pageNum = 1;
  228. getList();
  229. };
  230. /** 重置按钮操作 */
  231. const resetQuery = () => {
  232. queryFormRef.value?.resetFields();
  233. handleQuery();
  234. };
  235. /** 多选框选中数据 */
  236. const handleSelectionChange = (selection) => {
  237. ids.value = selection.map((item) => item.id);
  238. single.value = selection.length != 1;
  239. multiple.value = !selection.length;
  240. };
  241. /** 新增按钮操作 */
  242. const handleAdd = () => {
  243. reset();
  244. dialog.visible = true;
  245. dialog.title = '新增品牌型号';
  246. };
  247. /** 修改按钮操作 */
  248. const handleUpdate = async (row) => {
  249. reset();
  250. const _id = row?.id || ids.value[0];
  251. const res = await getDeviceTypeDetail(_id);
  252. res.data.ext1 = res.data.ext1 && JSON.parse(res.data.ext1);
  253. Object.assign(form.value, res.data);
  254. dialog.visible = true;
  255. dialog.title = '修改品牌型号';
  256. };
  257. /** 提交按钮 */
  258. const submitForm = () => {
  259. deviceTypeFormRef.value?.validate(async (valid: boolean) => {
  260. if (valid) {
  261. buttonLoading.value = true;
  262. const { ext1 } = form.value;
  263. const params = Object.assign(form.value, { ext1: JSON.stringify(ext1) });
  264. if (form.value.id) {
  265. await updateDeviceTypeDetail(params).finally(() => (buttonLoading.value = false));
  266. } else {
  267. await addDeviceTypeDetail(params).finally(() => (buttonLoading.value = false));
  268. }
  269. proxy?.$modal.msgSuccess('操作成功');
  270. dialog.visible = false;
  271. await getList();
  272. }
  273. });
  274. };
  275. /** 删除按钮操作 */
  276. const handleDelete = async (row) => {
  277. const _ids = row?.id || ids.value;
  278. await proxy?.$modal.confirm('是否确认删除?').finally(() => (loading.value = false));
  279. await delDeviceTypeDetail(_ids);
  280. proxy?.$modal.msgSuccess('删除成功');
  281. await getList();
  282. };
  283. const getTreeData = async () => {
  284. getDeviceSystemTree({}).then(({ code, rows }) => {
  285. if (code === 200) {
  286. treeData.value = convertToTree(rows);
  287. if (treeData.value.length === 0) {
  288. treeData.value = [];
  289. }
  290. }
  291. });
  292. };
  293. const convertToTree = (list) => {
  294. let map = new Map();
  295. let root = [];
  296. for (let item of list) {
  297. map.set(item.id, { ...item });
  298. }
  299. for (let item of list) {
  300. if (item.parentId !== 0) {
  301. let parent = map.get(item.parentId);
  302. if (!parent.children) {
  303. parent.children = [];
  304. }
  305. parent.children.push(map.get(item.id));
  306. } else {
  307. root.push(map.get(item.id));
  308. }
  309. }
  310. return root;
  311. };
  312. const findNameWithParents = (data, idToFind, parentName = '') => {
  313. for (let item of data) {
  314. let fullName = parentName ? `${parentName}/${item.name}` : item.name;
  315. if (item.id === idToFind) {
  316. return fullName;
  317. }
  318. if (item.children && Array.isArray(item.children)) {
  319. let result = findNameWithParents(item.children, idToFind, fullName);
  320. if (result) {
  321. return result;
  322. }
  323. }
  324. }
  325. return null; // 如果没有找到对应的 ID,则返回 null
  326. };
  327. const getDeviceTypeList = () => {
  328. listDeviceType({}).then(({ code, rows }) => {
  329. if (code === 200) {
  330. dictGroup.deviceTypeOptions = rows;
  331. }
  332. });
  333. };
  334. const getProductorList = () => {
  335. listProductor({}).then(({ code, rows }) => {
  336. if (code === 200) {
  337. dictGroup.productorOptions = rows;
  338. }
  339. });
  340. };
  341. const setProductorInfo = (val) => {
  342. const [{ contact, phone,name }] = dictGroup.productorOptions.filter((item) => item.id === val);
  343. form.value.ext1.linkName = contact;
  344. form.value.ext1.productorName = name;
  345. form.value.ext1.linkPhone = phone;
  346. };
  347. const handleNodeClick = (data, node) => {
  348. queryParams.value.systemId = data.id;
  349. handleQuery();
  350. };
  351. const formatDict = (val, option: string) => {
  352. let label = '';
  353. dictGroup[option].forEach((item) => {
  354. if (val === item.id) {
  355. label = item.name;
  356. }
  357. });
  358. return label;
  359. };
  360. onMounted(() => {
  361. getList();
  362. getTreeData();
  363. getDeviceTypeList();
  364. getProductorList();
  365. });
  366. </script>
  367. <style lang="scss" scoped></style>