|
@@ -1,9 +1,57 @@
|
|
<template>
|
|
<template>
|
|
<div class="registration-query flex flex-col h-full">
|
|
<div class="registration-query flex flex-col h-full">
|
|
|
|
+ <SearchForm :fields="fields" :params="params">
|
|
|
|
+ <template #supplier="{ item, params }">
|
|
|
|
+ <select-supplier
|
|
|
|
+ v-model="params[item.prop]"
|
|
|
|
+ type="DEVICE"
|
|
|
|
+ ></select-supplier>
|
|
|
|
+ </template>
|
|
|
|
+ <template #brand="{ item, params }">
|
|
|
|
+ <t-select
|
|
|
|
+ v-model="params[item.prop]"
|
|
|
|
+ :options="brandList"
|
|
|
|
+ clearable
|
|
|
|
+ @change="brandChange"
|
|
|
|
+ />
|
|
|
|
+ </template>
|
|
|
|
+ <template #model="{ item, params }">
|
|
|
|
+ <t-select
|
|
|
|
+ v-model="params[item.prop]"
|
|
|
|
+ :options="brandModelList"
|
|
|
|
+ clearable
|
|
|
|
+ />
|
|
|
|
+ </template>
|
|
|
|
+ </SearchForm>
|
|
<div class="flex-1 page-wrap">
|
|
<div class="flex-1 page-wrap">
|
|
- <div class="btn-group">
|
|
|
|
- <t-button theme="success" @click="handleAdd">新增</t-button>
|
|
|
|
- </div>
|
|
|
|
|
|
+ <t-space size="small">
|
|
|
|
+ <t-button theme="success" @click="handleAdd">新增设备</t-button>
|
|
|
|
+ <t-button
|
|
|
|
+ theme="danger"
|
|
|
|
+ :disabled="!selectedRowKeys.length"
|
|
|
|
+ @click="handleDestroy"
|
|
|
|
+ >批量作废</t-button
|
|
|
|
+ >
|
|
|
|
+ <t-button
|
|
|
|
+ theme="success"
|
|
|
|
+ :disabled="!selectedRowKeys.length"
|
|
|
|
+ @click="handleEable(selectedRowKeys, true)"
|
|
|
|
+ >批量启用</t-button
|
|
|
|
+ >
|
|
|
|
+ <t-button
|
|
|
|
+ theme="danger"
|
|
|
|
+ :disabled="!selectedRowKeys.length"
|
|
|
|
+ @click="handleEable(selectedRowKeys, false)"
|
|
|
|
+ >批量禁用</t-button
|
|
|
|
+ >
|
|
|
|
+ <upload-button
|
|
|
|
+ upload-url="/api/sys/device/import"
|
|
|
|
+ :button-props="{
|
|
|
|
+ content: '批量导入',
|
|
|
|
+ theme: 'success',
|
|
|
|
+ }"
|
|
|
|
+ ></upload-button>
|
|
|
|
+ </t-space>
|
|
<t-table
|
|
<t-table
|
|
size="small"
|
|
size="small"
|
|
row-key="id"
|
|
row-key="id"
|
|
@@ -15,22 +63,35 @@
|
|
defaultPageSize: 10,
|
|
defaultPageSize: 10,
|
|
onChange,
|
|
onChange,
|
|
total: pagination.total,
|
|
total: pagination.total,
|
|
|
|
+ current: pagination.pageNumber,
|
|
}"
|
|
}"
|
|
v-loading="tableLoading"
|
|
v-loading="tableLoading"
|
|
|
|
+ :selected-row-keys="selectedRowKeys"
|
|
|
|
+ @select-change="selectChange"
|
|
>
|
|
>
|
|
|
|
+ <template #enable="{ col, row }">
|
|
|
|
+ {{ enableFilter(row[col.colKey]) }}
|
|
|
|
+ </template>
|
|
<template #buy-time="{ col, row }">
|
|
<template #buy-time="{ col, row }">
|
|
{{ timestampFilter(row[col.colKey]) }}
|
|
{{ timestampFilter(row[col.colKey]) }}
|
|
</template>
|
|
</template>
|
|
<template #status="{ col, row }">
|
|
<template #status="{ col, row }">
|
|
{{ runningStatusFilter(row[col.colKey]) }}
|
|
{{ runningStatusFilter(row[col.colKey]) }}
|
|
</template>
|
|
</template>
|
|
|
|
+ <template #bound="{ col, row }">
|
|
|
|
+ {{ inoutTypeFilter(row[col.colKey]) }}
|
|
|
|
+ </template>
|
|
<template #operate="{ row }">
|
|
<template #operate="{ row }">
|
|
<div class="table-operations">
|
|
<div class="table-operations">
|
|
<t-link theme="primary" hover="color" @click="handleEdit(row)">
|
|
<t-link theme="primary" hover="color" @click="handleEdit(row)">
|
|
修改
|
|
修改
|
|
</t-link>
|
|
</t-link>
|
|
- <t-link theme="danger" hover="color" @click="handleDestroy(row)">
|
|
|
|
- 作废
|
|
|
|
|
|
+ <t-link
|
|
|
|
+ :theme="row.enable ? 'danger' : 'success'"
|
|
|
|
+ hover="color"
|
|
|
|
+ @click="handleEable([row.id], !row.enable)"
|
|
|
|
+ >
|
|
|
|
+ {{ row.enable ? '禁用' : '启用' }}
|
|
</t-link>
|
|
</t-link>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
@@ -40,31 +101,171 @@
|
|
<edit-device-dialog
|
|
<edit-device-dialog
|
|
v-model:visible="showEditDeviceDialog"
|
|
v-model:visible="showEditDeviceDialog"
|
|
:curRow="curRow"
|
|
:curRow="curRow"
|
|
|
|
+ :brand-list="brandList"
|
|
@success="fetchData"
|
|
@success="fetchData"
|
|
></edit-device-dialog>
|
|
></edit-device-dialog>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script setup name="DeviceManage">
|
|
<script setup name="DeviceManage">
|
|
-import { ref } from 'vue';
|
|
|
|
|
|
+import { ref, reactive, onMounted } from 'vue';
|
|
import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
|
|
import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
|
|
import useFetchTable from '@/hooks/useFetchTable';
|
|
import useFetchTable from '@/hooks/useFetchTable';
|
|
import EditDeviceDialog from './edit-device-dialog.vue';
|
|
import EditDeviceDialog from './edit-device-dialog.vue';
|
|
-import { deviceQueryApi, deviceDestroyApi } from '@/api/system';
|
|
|
|
-import { runningStatusFilter, timestampFilter } from '@/utils/filter';
|
|
|
|
|
|
+import {
|
|
|
|
+ deviceQueryApi,
|
|
|
|
+ deviceDestroyApi,
|
|
|
|
+ deviceEnableApi,
|
|
|
|
+ deviceBrandListApi,
|
|
|
|
+} from '@/api/system';
|
|
|
|
+import {
|
|
|
|
+ runningStatusFilter,
|
|
|
|
+ timestampFilter,
|
|
|
|
+ enableFilter,
|
|
|
|
+ inoutTypeFilter,
|
|
|
|
+} from '@/utils/filter';
|
|
|
|
+import { dictToOptionList } from '@/utils/tool';
|
|
|
|
+import { ABLE_TYPE, RUNNING_STATUS, INOUT_TYPE } from '@/config/constants';
|
|
|
|
|
|
const showEditDeviceDialog = ref(false);
|
|
const showEditDeviceDialog = ref(false);
|
|
const curRow = ref(null);
|
|
const curRow = ref(null);
|
|
|
|
+const selectedRowKeys = ref([]);
|
|
|
|
+const brandList = ref([]);
|
|
|
|
+const brandModelList = ref([]);
|
|
|
|
+
|
|
|
|
+const getBrandList = async () => {
|
|
|
|
+ const res = await deviceBrandListApi().catch(() => {});
|
|
|
|
+ if (!res) return;
|
|
|
|
+ brandList.value = res.map((item) => {
|
|
|
|
+ return {
|
|
|
|
+ label: item.brand,
|
|
|
|
+ value: item.brand,
|
|
|
|
+ list: item.list.map((elem) => {
|
|
|
|
+ return {
|
|
|
|
+ label: elem.model,
|
|
|
|
+ value: elem.model,
|
|
|
|
+ };
|
|
|
|
+ }),
|
|
|
|
+ };
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+const brandChange = () => {
|
|
|
|
+ params.model = '';
|
|
|
|
+ brandModelList.value = [];
|
|
|
|
+ getBrandModelList(params.brand);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const getBrandModelList = (brand) => {
|
|
|
|
+ const curBrand = brandList.value.find((item) => item.value === brand);
|
|
|
|
+ if (!curBrand) {
|
|
|
|
+ brandModelList.value = [];
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ brandModelList.value = curBrand.list;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const fields = ref([
|
|
|
|
+ {
|
|
|
|
+ prop: 'supplierId',
|
|
|
|
+ label: '设备供应商',
|
|
|
|
+ type: 'select',
|
|
|
|
+ labelWidth: 100,
|
|
|
|
+ colSpan: 5,
|
|
|
|
+ cell: 'supplier',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ prop: 'brand',
|
|
|
|
+ label: '品牌',
|
|
|
|
+ type: 'select',
|
|
|
|
+ labelWidth: 60,
|
|
|
|
+ colSpan: 5,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ prop: 'model',
|
|
|
|
+ label: '型号',
|
|
|
|
+ type: 'select',
|
|
|
|
+ labelWidth: 60,
|
|
|
|
+ colSpan: 5,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ prop: 'deviceCode',
|
|
|
|
+ label: '设备编号',
|
|
|
|
+ labelWidth: 100,
|
|
|
|
+ colSpan: 5,
|
|
|
|
+ attrs: {
|
|
|
|
+ clearable: true,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ type: 'buttons',
|
|
|
|
+ colSpan: 2,
|
|
|
|
+ children: [
|
|
|
|
+ {
|
|
|
|
+ type: 'button',
|
|
|
|
+ text: '查询',
|
|
|
|
+ onClick: () => {
|
|
|
|
+ search();
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ prop: 'status',
|
|
|
|
+ label: '运行状态',
|
|
|
|
+ type: 'select',
|
|
|
|
+ labelWidth: 100,
|
|
|
|
+ colSpan: 5,
|
|
|
|
+ options: dictToOptionList(RUNNING_STATUS),
|
|
|
|
+ attrs: {
|
|
|
|
+ clearable: true,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ prop: 'bound',
|
|
|
|
+ label: '出库/入库',
|
|
|
|
+ type: 'select',
|
|
|
|
+ labelWidth: 100,
|
|
|
|
+ colSpan: 5,
|
|
|
|
+ options: dictToOptionList(INOUT_TYPE),
|
|
|
|
+ attrs: {
|
|
|
|
+ clearable: true,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ prop: 'enable',
|
|
|
|
+ label: '启用/禁用',
|
|
|
|
+ type: 'select',
|
|
|
|
+ labelWidth: 100,
|
|
|
|
+ colSpan: 5,
|
|
|
|
+ options: dictToOptionList(ABLE_TYPE),
|
|
|
|
+ attrs: {
|
|
|
|
+ clearable: true,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+]);
|
|
|
|
+const params = reactive({
|
|
|
|
+ supplierId: '',
|
|
|
|
+ brand: '',
|
|
|
|
+ model: '',
|
|
|
|
+ deviceCode: '',
|
|
|
|
+ status: '',
|
|
|
|
+ bound: '',
|
|
|
|
+ enable: '',
|
|
|
|
+});
|
|
|
|
|
|
const columns = [
|
|
const columns = [
|
|
- { colKey: 'name', title: '设备编号' },
|
|
|
|
|
|
+ { colKey: 'row-select', type: 'multiple', width: 50 },
|
|
|
|
+ { colKey: 'deviceCode', title: '设备编号' },
|
|
{ colKey: 'serialNo', title: '序列号' },
|
|
{ colKey: 'serialNo', title: '序列号' },
|
|
{ colKey: 'brand', title: '品牌' },
|
|
{ colKey: 'brand', title: '品牌' },
|
|
|
|
+ { colKey: 'model', title: '型号' },
|
|
{ colKey: 'buyTime', title: '购买时间', cell: 'buy-time', width: 170 },
|
|
{ colKey: 'buyTime', title: '购买时间', cell: 'buy-time', width: 170 },
|
|
- { colKey: 'supplier', title: '供应商' },
|
|
|
|
|
|
+ { colKey: 'supplier', title: '设备供应商' },
|
|
{ colKey: 'status', title: '运行状态', cell: 'status', width: 80 },
|
|
{ colKey: 'status', title: '运行状态', cell: 'status', width: 80 },
|
|
{ colKey: 'location', title: '当前所在地' },
|
|
{ colKey: 'location', title: '当前所在地' },
|
|
{ colKey: 'scanCount', title: '总扫描量', width: 80 },
|
|
{ colKey: 'scanCount', title: '总扫描量', width: 80 },
|
|
|
|
+ { colKey: 'bound', title: '出库/入库', width: 100 },
|
|
|
|
+ { colKey: 'enable', title: '启用/禁用', width: 100 },
|
|
{
|
|
{
|
|
title: '操作',
|
|
title: '操作',
|
|
colKey: 'operate',
|
|
colKey: 'operate',
|
|
@@ -79,14 +280,24 @@ const {
|
|
pagination,
|
|
pagination,
|
|
tableData,
|
|
tableData,
|
|
fetchData,
|
|
fetchData,
|
|
|
|
+ search,
|
|
onChange,
|
|
onChange,
|
|
} = useFetchTable(deviceQueryApi);
|
|
} = useFetchTable(deviceQueryApi);
|
|
|
|
|
|
|
|
+const selectChange = (value) => {
|
|
|
|
+ selectedRowKeys.value = value;
|
|
|
|
+};
|
|
const handleAdd = () => {
|
|
const handleAdd = () => {
|
|
curRow.value = null;
|
|
curRow.value = null;
|
|
showEditDeviceDialog.value = true;
|
|
showEditDeviceDialog.value = true;
|
|
};
|
|
};
|
|
-const handleDestroy = (row) => {
|
|
|
|
|
|
+
|
|
|
|
+const handleDestroy = () => {
|
|
|
|
+ if (!selectedRowKeys.value.length) {
|
|
|
|
+ MessagePlugin.error('请选择要作废的记录');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
const confirmDia = DialogPlugin({
|
|
const confirmDia = DialogPlugin({
|
|
header: '操作提示',
|
|
header: '操作提示',
|
|
body: `确定要作废选中的记录吗`,
|
|
body: `确定要作废选中的记录吗`,
|
|
@@ -94,15 +305,42 @@ const handleDestroy = (row) => {
|
|
cancelBtn: '取消',
|
|
cancelBtn: '取消',
|
|
onConfirm: async () => {
|
|
onConfirm: async () => {
|
|
confirmDia.hide();
|
|
confirmDia.hide();
|
|
- const res = await deviceDestroyApi(row.id).catch(() => {});
|
|
|
|
|
|
+ const res = await deviceDestroyApi(selectedRowKeys.value).catch(() => {});
|
|
if (!res) return;
|
|
if (!res) return;
|
|
MessagePlugin.success('删除成功');
|
|
MessagePlugin.success('删除成功');
|
|
fetchData();
|
|
fetchData();
|
|
},
|
|
},
|
|
});
|
|
});
|
|
};
|
|
};
|
|
|
|
+const handleEable = (selectedIds, enable) => {
|
|
|
|
+ const name = enable ? '启用' : '禁用';
|
|
|
|
+
|
|
|
|
+ if (!selectedIds.length) {
|
|
|
|
+ MessagePlugin.error(`请选择要${name}的记录`);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const confirmDia = DialogPlugin({
|
|
|
|
+ header: `${name}提示`,
|
|
|
|
+ body: `确定要${name}选中的记录吗`,
|
|
|
|
+ confirmBtn: '确定',
|
|
|
|
+ cancelBtn: '取消',
|
|
|
|
+ onConfirm: async () => {
|
|
|
|
+ confirmDia.hide();
|
|
|
|
+ const res = await deviceEnableApi(selectedIds, enable).catch(() => {});
|
|
|
|
+ if (!res) return;
|
|
|
|
+ MessagePlugin.success('操作成功');
|
|
|
|
+ fetchData();
|
|
|
|
+ },
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+
|
|
const handleEdit = (row) => {
|
|
const handleEdit = (row) => {
|
|
curRow.value = row;
|
|
curRow.value = row;
|
|
showEditDeviceDialog.value = true;
|
|
showEditDeviceDialog.value = true;
|
|
};
|
|
};
|
|
|
|
+
|
|
|
|
+onMounted(() => {
|
|
|
|
+ getBrandList();
|
|
|
|
+});
|
|
</script>
|
|
</script>
|