This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
:show-expand="false"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
@@ -73,45 +74,55 @@
|
||||
<ElDialog
|
||||
v-model="allocateDialogVisible"
|
||||
:title="$t('enterpriseDevices.dialog.allocateTitle')"
|
||||
width="700px"
|
||||
width="75%"
|
||||
@close="handleAllocateDialogClose"
|
||||
>
|
||||
<ElForm
|
||||
ref="allocateFormRef"
|
||||
:model="allocateForm"
|
||||
:rules="allocateRules"
|
||||
label-width="120px"
|
||||
<!-- 搜索过滤条件 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="deviceSearchForm"
|
||||
:items="deviceSearchFormItems"
|
||||
label-width="85"
|
||||
:show-expand="false"
|
||||
@reset="handleDeviceSearchReset"
|
||||
@search="handleDeviceSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<!-- 设备列表 -->
|
||||
<div class="device-selection-info">
|
||||
已选择 {{ selectedAvailableDevices.length }} 台设备
|
||||
</div>
|
||||
<ArtTable
|
||||
ref="availableDevicesTableRef"
|
||||
row-key="id"
|
||||
:loading="availableDevicesLoading"
|
||||
:data="availableDevicesList"
|
||||
:currentPage="devicePagination.page"
|
||||
:pageSize="devicePagination.pageSize"
|
||||
:total="devicePagination.total"
|
||||
:marginTop="10"
|
||||
@size-change="handleDevicePageSizeChange"
|
||||
@current-change="handleDevicePageChange"
|
||||
@selection-change="handleAvailableDevicesSelectionChange"
|
||||
>
|
||||
<ElFormItem :label="$t('enterpriseDevices.form.deviceNos')" prop="virtual_nos">
|
||||
<ElInput
|
||||
v-model="deviceNosText"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
:placeholder="$t('enterpriseDevices.form.deviceNosPlaceholder')"
|
||||
@input="handleDeviceNosChange"
|
||||
<template #default>
|
||||
<ElTableColumn type="selection" width="55" :selectable="checkDeviceSelectable" />
|
||||
<ElTableColumn
|
||||
v-for="col in availableDeviceColumns"
|
||||
:key="col.prop || col.type"
|
||||
v-bind="col"
|
||||
/>
|
||||
<div style="margin-top: 4px; font-size: 12px; color: var(--el-color-info)">
|
||||
{{
|
||||
$t('enterpriseDevices.form.selectedCount', {
|
||||
count: allocateForm.virtual_nos?.length || 0
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem :label="$t('enterpriseDevices.form.remark')">
|
||||
<ElInput
|
||||
v-model="allocateForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
:placeholder="$t('enterpriseDevices.form.remarkPlaceholder')"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="allocateDialogVisible = false">{{ $t('common.cancel') }}</ElButton>
|
||||
<ElButton type="primary" @click="handleAllocate" :loading="allocateLoading">
|
||||
<ElButton
|
||||
type="primary"
|
||||
@click="handleAllocate"
|
||||
:loading="allocateLoading"
|
||||
:disabled="selectedAvailableDevices.length === 0"
|
||||
>
|
||||
{{ $t('common.confirm') }}
|
||||
</ElButton>
|
||||
</div>
|
||||
@@ -225,7 +236,7 @@
|
||||
import { h } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { EnterpriseService } from '@/api/modules'
|
||||
import { EnterpriseService, DeviceService } from '@/api/modules'
|
||||
import { ElMessage, ElMessageBox, ElTag } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
@@ -239,6 +250,7 @@
|
||||
FailedDeviceItem
|
||||
} from '@/types/api/enterpriseDevice'
|
||||
import type { EnterpriseItem } from '@/types/api'
|
||||
import type { Device, DeviceStatus } from '@/types/api/device'
|
||||
|
||||
defineOptions({ name: 'EnterpriseDevices' })
|
||||
|
||||
@@ -252,12 +264,10 @@
|
||||
const recallLoading = ref(false)
|
||||
const resultDialogVisible = ref(false)
|
||||
const tableRef = ref()
|
||||
const allocateFormRef = ref<FormInstance>()
|
||||
const recallFormRef = ref<FormInstance>()
|
||||
const selectedDevices = ref<EnterpriseDeviceItem[]>([])
|
||||
const enterpriseId = ref<number>(0)
|
||||
const enterpriseInfo = ref<EnterpriseItem | null>(null)
|
||||
const deviceNosText = ref('')
|
||||
const operationResult = ref<AllocateDevicesResponse | RecallDevicesResponse>({
|
||||
success_count: 0,
|
||||
fail_count: 0,
|
||||
@@ -265,6 +275,28 @@
|
||||
authorized_devices: null
|
||||
})
|
||||
|
||||
// 可用设备列表相关
|
||||
const availableDevicesTableRef = ref()
|
||||
const availableDevicesLoading = ref(false)
|
||||
const availableDevicesList = ref<Device[]>([])
|
||||
const selectedAvailableDevices = ref<Device[]>([])
|
||||
const allocatedDeviceVirtualNos = ref<Set<string>>(new Set())
|
||||
|
||||
// 设备搜索表单初始值
|
||||
const initialDeviceSearchState = {
|
||||
status: undefined,
|
||||
virtual_no: '',
|
||||
device_name: '',
|
||||
shop_id: undefined
|
||||
}
|
||||
|
||||
const deviceSearchForm = reactive({ ...initialDeviceSearchState })
|
||||
const devicePagination = reactive({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState = {
|
||||
virtual_no: ''
|
||||
@@ -273,31 +305,6 @@
|
||||
// 搜索表单
|
||||
const searchForm = reactive({ ...initialSearchState })
|
||||
|
||||
// 授权表单
|
||||
const allocateForm = reactive({
|
||||
virtual_nos: [] as string[],
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 授权表单验证规则
|
||||
const allocateRules = reactive<FormRules>({
|
||||
virtual_nos: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (!value || value.length === 0) {
|
||||
callback(new Error(t('enterpriseDevices.validation.deviceNosRequired')))
|
||||
} else if (value.length > 100) {
|
||||
callback(new Error(t('enterpriseDevices.validation.deviceNosMaxLength')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 撤销表单
|
||||
const recallForm = reactive({})
|
||||
|
||||
@@ -324,6 +331,43 @@
|
||||
}
|
||||
]
|
||||
|
||||
// 设备列表搜索表单配置
|
||||
const deviceSearchFormItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '设备状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '在库', value: 1 },
|
||||
{ label: '已分销', value: 2 },
|
||||
{ label: '已激活', value: 3 },
|
||||
{ label: '已停用', value: 4 }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '设备号',
|
||||
prop: 'virtual_no',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入设备号'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '设备名称',
|
||||
prop: 'device_name',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入设备名称'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: t('enterpriseDevices.table.deviceId'), prop: 'device_id' },
|
||||
@@ -336,6 +380,38 @@
|
||||
|
||||
const deviceList = ref<EnterpriseDeviceItem[]>([])
|
||||
|
||||
// 获取设备状态标签类型
|
||||
const getDeviceStatusTag = (status: DeviceStatus) => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return 'info'
|
||||
case 2:
|
||||
return 'warning'
|
||||
case 3:
|
||||
return 'success'
|
||||
case 4:
|
||||
return 'danger'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取设备状态文本
|
||||
const getDeviceStatusText = (status: DeviceStatus) => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return '在库'
|
||||
case 2:
|
||||
return '已分销'
|
||||
case 3:
|
||||
return '已激活'
|
||||
case 4:
|
||||
return '已停用'
|
||||
default:
|
||||
return '未知'
|
||||
}
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
@@ -372,6 +448,45 @@
|
||||
}
|
||||
])
|
||||
|
||||
// 可用设备列表列配置
|
||||
const availableDeviceColumns = computed(() => [
|
||||
{
|
||||
prop: 'virtual_no',
|
||||
label: '设备号',
|
||||
minWidth: 150
|
||||
},
|
||||
{
|
||||
prop: 'device_name',
|
||||
label: '设备名称',
|
||||
minWidth: 150
|
||||
},
|
||||
{
|
||||
prop: 'device_model',
|
||||
label: '设备型号',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: Device) => {
|
||||
return h(ElTag, { type: getDeviceStatusTag(row.status) }, () =>
|
||||
getDeviceStatusText(row.status)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'shop_name',
|
||||
label: '所属店铺',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
prop: 'bound_card_count',
|
||||
label: '绑定卡数',
|
||||
width: 100
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
const id = route.query.id
|
||||
if (id) {
|
||||
@@ -469,86 +584,130 @@
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 显示授权对话框
|
||||
const showAllocateDialog = () => {
|
||||
allocateDialogVisible.value = true
|
||||
deviceNosText.value = ''
|
||||
allocateForm.virtual_nos = []
|
||||
allocateForm.remark = ''
|
||||
if (allocateFormRef.value) {
|
||||
allocateFormRef.value.resetFields()
|
||||
// 获取可用设备列表
|
||||
const getAvailableDevicesList = async () => {
|
||||
availableDevicesLoading.value = true
|
||||
try {
|
||||
const params: any = {
|
||||
page: devicePagination.page,
|
||||
page_size: devicePagination.pageSize,
|
||||
...deviceSearchForm
|
||||
}
|
||||
// 清理空值
|
||||
Object.keys(params).forEach((key) => {
|
||||
if (params[key] === '' || params[key] === undefined) {
|
||||
delete params[key]
|
||||
}
|
||||
})
|
||||
|
||||
const res = await DeviceService.getDevices(params)
|
||||
if (res.code === 0) {
|
||||
availableDevicesList.value = res.data.items || []
|
||||
devicePagination.total = res.data.total || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error('获取设备列表失败')
|
||||
} finally {
|
||||
availableDevicesLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理设备号输入变化
|
||||
const handleDeviceNosChange = () => {
|
||||
// 解析输入的设备号,支持逗号、空格、换行分隔
|
||||
const deviceNos = deviceNosText.value
|
||||
.split(/[,\s\n]+/)
|
||||
.map((no) => no.trim())
|
||||
.filter((no) => no.length > 0)
|
||||
allocateForm.virtual_nos = deviceNos
|
||||
// 处理设备列表选择变化
|
||||
const handleAvailableDevicesSelectionChange = (selection: Device[]) => {
|
||||
selectedAvailableDevices.value = selection
|
||||
}
|
||||
|
||||
// 设备列表搜索
|
||||
const handleDeviceSearch = () => {
|
||||
devicePagination.page = 1
|
||||
getAvailableDevicesList()
|
||||
}
|
||||
|
||||
// 设备列表重置
|
||||
const handleDeviceSearchReset = () => {
|
||||
Object.assign(deviceSearchForm, { ...initialDeviceSearchState })
|
||||
devicePagination.page = 1
|
||||
getAvailableDevicesList()
|
||||
}
|
||||
|
||||
// 设备列表分页大小变化
|
||||
const handleDevicePageSizeChange = (newPageSize: number) => {
|
||||
devicePagination.pageSize = newPageSize
|
||||
getAvailableDevicesList()
|
||||
}
|
||||
|
||||
// 设备列表页码变化
|
||||
const handleDevicePageChange = (newPage: number) => {
|
||||
devicePagination.page = newPage
|
||||
getAvailableDevicesList()
|
||||
}
|
||||
|
||||
// 检查设备是否可选(已授权的设备不可选)
|
||||
const checkDeviceSelectable = (row: Device) => {
|
||||
return !allocatedDeviceVirtualNos.value.has(row.virtual_no)
|
||||
}
|
||||
|
||||
// 显示授权对话框
|
||||
const showAllocateDialog = () => {
|
||||
allocateDialogVisible.value = true
|
||||
selectedAvailableDevices.value = []
|
||||
// 收集已授权的设备的 virtual_no
|
||||
allocatedDeviceVirtualNos.value = new Set(deviceList.value.map((device) => device.virtual_no))
|
||||
// 重置搜索条件
|
||||
Object.assign(deviceSearchForm, { ...initialDeviceSearchState })
|
||||
devicePagination.page = 1
|
||||
devicePagination.pageSize = 20
|
||||
// 加载可用设备列表
|
||||
getAvailableDevicesList()
|
||||
}
|
||||
|
||||
// 执行授权
|
||||
const handleAllocate = async () => {
|
||||
if (!allocateFormRef.value) return
|
||||
if (selectedAvailableDevices.value.length === 0) {
|
||||
ElMessage.warning('请选择要授权的设备')
|
||||
return
|
||||
}
|
||||
|
||||
await allocateFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if (allocateForm.virtual_nos.length === 0) {
|
||||
ElMessage.warning(t('enterpriseDevices.messages.deviceNosEmpty'))
|
||||
return
|
||||
}
|
||||
allocateLoading.value = true
|
||||
try {
|
||||
const device_nos = selectedAvailableDevices.value.map((device) => device.virtual_no)
|
||||
const res = await EnterpriseService.allocateDevices(enterpriseId.value, {
|
||||
device_nos
|
||||
})
|
||||
|
||||
if (allocateForm.virtual_nos.length > 100) {
|
||||
ElMessage.warning(t('enterpriseDevices.messages.deviceNosMaxLimit'))
|
||||
return
|
||||
}
|
||||
if (res.code === 0) {
|
||||
operationResult.value = res.data
|
||||
allocateDialogVisible.value = false
|
||||
resultDialogVisible.value = true
|
||||
|
||||
allocateLoading.value = true
|
||||
try {
|
||||
const res = await EnterpriseService.allocateDevices(enterpriseId.value, {
|
||||
virtual_nos: allocateForm.virtual_nos,
|
||||
remark: allocateForm.remark || undefined
|
||||
})
|
||||
|
||||
if (res.code === 0) {
|
||||
operationResult.value = res.data
|
||||
allocateDialogVisible.value = false
|
||||
resultDialogVisible.value = true
|
||||
|
||||
// 显示成功消息
|
||||
if (res.data.success_count > 0 && res.data.fail_count === 0) {
|
||||
ElMessage.success(t('enterpriseDevices.messages.allocateSuccess'))
|
||||
} else if (res.data.success_count > 0 && res.data.fail_count > 0) {
|
||||
ElMessage.warning(
|
||||
t('enterpriseDevices.messages.allocatePartialSuccess', {
|
||||
success: res.data.success_count,
|
||||
fail: res.data.fail_count
|
||||
})
|
||||
)
|
||||
} else {
|
||||
ElMessage.error(t('enterpriseDevices.messages.allocateFailed'))
|
||||
}
|
||||
|
||||
getTableData()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
// 显示成功消息
|
||||
if (res.data.success_count > 0 && res.data.fail_count === 0) {
|
||||
ElMessage.success(t('enterpriseDevices.messages.allocateSuccess'))
|
||||
} else if (res.data.success_count > 0 && res.data.fail_count > 0) {
|
||||
ElMessage.warning(
|
||||
t('enterpriseDevices.messages.allocatePartialSuccess', {
|
||||
success: res.data.success_count,
|
||||
fail: res.data.fail_count
|
||||
})
|
||||
)
|
||||
} else {
|
||||
ElMessage.error(t('enterpriseDevices.messages.allocateFailed'))
|
||||
} finally {
|
||||
allocateLoading.value = false
|
||||
}
|
||||
|
||||
getTableData()
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error(t('enterpriseDevices.messages.allocateFailed'))
|
||||
} finally {
|
||||
allocateLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭授权对话框
|
||||
const handleAllocateDialogClose = () => {
|
||||
if (allocateFormRef.value) {
|
||||
allocateFormRef.value.resetFields()
|
||||
}
|
||||
selectedAvailableDevices.value = []
|
||||
}
|
||||
|
||||
// 显示撤销授权对话框
|
||||
@@ -582,7 +741,7 @@
|
||||
recallLoading.value = true
|
||||
try {
|
||||
const res = await EnterpriseService.recallDevices(enterpriseId.value, {
|
||||
virtual_nos: selectedDevices.value.map((device) => device.virtual_no)
|
||||
device_nos: selectedDevices.value.map((device) => device.virtual_no)
|
||||
})
|
||||
|
||||
if (res.code === 0) {
|
||||
@@ -636,5 +795,12 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.device-selection-info {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 12px;
|
||||
color: var(--el-color-info);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user