feat: 资产管理新增字段
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 1m47s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 1m47s
This commit is contained in:
@@ -26,6 +26,7 @@ export interface EnterpriseCardsParams {
|
|||||||
carrier_id?: number // 运营商ID
|
carrier_id?: number // 运营商ID
|
||||||
iccid?: string // ICCID (模糊查询)
|
iccid?: string // ICCID (模糊查询)
|
||||||
virtual_no?: string // 虚拟号 (模糊查询)
|
virtual_no?: string // 虚拟号 (模糊查询)
|
||||||
|
msisdn?: string // 接入号 (模糊查询)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +35,10 @@ export interface EnterpriseCardsParams {
|
|||||||
export interface EnterpriseDevicesParams {
|
export interface EnterpriseDevicesParams {
|
||||||
page?: number
|
page?: number
|
||||||
page_size?: number
|
page_size?: number
|
||||||
|
status?: number
|
||||||
|
device_name?: string // 设备号 / 设备名称 (模糊搜索)
|
||||||
virtual_no?: string // 虚拟号 (模糊搜索)
|
virtual_no?: string // 虚拟号 (模糊搜索)
|
||||||
|
imei?: string // IMEI (模糊搜索)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ interface Props {
|
|||||||
show: boolean
|
show: boolean
|
||||||
options: PickerOption[]
|
options: PickerOption[]
|
||||||
title?: string
|
title?: string
|
||||||
|
autoConfirm?: boolean
|
||||||
|
selectedValue?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
@@ -19,13 +21,42 @@ interface Emits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
title: '请选择'
|
title: '请选择',
|
||||||
|
autoConfirm: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits<Emits>()
|
const emit = defineEmits<Emits>()
|
||||||
|
|
||||||
const selectedIndex = ref(0)
|
const selectedIndex = ref(0)
|
||||||
|
|
||||||
|
function syncSelectedIndex() {
|
||||||
|
if (!props.options.length) {
|
||||||
|
selectedIndex.value = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchedIndex = props.options.findIndex(option => option.value === props.selectedValue)
|
||||||
|
selectedIndex.value = matchedIndex >= 0 ? matchedIndex : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => props.show, (show) => {
|
||||||
|
if (show) {
|
||||||
|
syncSelectedIndex()
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
watch(() => props.selectedValue, () => {
|
||||||
|
if (props.show) {
|
||||||
|
syncSelectedIndex()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.options, () => {
|
||||||
|
if (props.show) {
|
||||||
|
syncSelectedIndex()
|
||||||
|
}
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
function close() {
|
function close() {
|
||||||
emit('update:show', false)
|
emit('update:show', false)
|
||||||
@@ -48,6 +79,11 @@ function handleConfirm() {
|
|||||||
// 选择选项
|
// 选择选项
|
||||||
function selectOption(index: number) {
|
function selectOption(index: number) {
|
||||||
selectedIndex.value = index
|
selectedIndex.value = index
|
||||||
|
|
||||||
|
if (props.autoConfirm && props.options[index]) {
|
||||||
|
emit('confirm', props.options[index])
|
||||||
|
close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -69,9 +105,17 @@ function selectOption(index: number) {
|
|||||||
<view class="simple-picker-title">
|
<view class="simple-picker-title">
|
||||||
<text class="text-base font-600 text-[#1e293b]">{{ title }}</text>
|
<text class="text-base font-600 text-[#1e293b]">{{ title }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="simple-picker-confirm" @click="handleConfirm">
|
<view
|
||||||
|
v-if="!autoConfirm"
|
||||||
|
class="simple-picker-confirm"
|
||||||
|
@click="handleConfirm"
|
||||||
|
>
|
||||||
<text class="text-sm text-brand font-600">确定</text>
|
<text class="text-sm text-brand font-600">确定</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view
|
||||||
|
v-else
|
||||||
|
class="simple-picker-confirm"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 选项列表 -->
|
<!-- 选项列表 -->
|
||||||
|
|||||||
@@ -454,7 +454,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 最后同步时间 -->
|
<!-- 最后同步时间 -->
|
||||||
<view v-if="realtimeStatus.last_sync_time"
|
<view
|
||||||
class="flex items-center justify-between pt-1 border-t-1px border-[#e5e7eb]">
|
class="flex items-center justify-between pt-1 border-t-1px border-[#e5e7eb]">
|
||||||
<text class="text-11px text-[#999]">最后同步</text>
|
<text class="text-11px text-[#999]">最后同步</text>
|
||||||
<text class="text-11px text-[#999]">
|
<text class="text-11px text-[#999]">
|
||||||
|
|||||||
@@ -80,13 +80,54 @@
|
|||||||
deviceStart: 'asset:device_start_h5',
|
deviceStart: 'asset:device_start_h5',
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
|
type CardSearchType = 'iccid' | 'virtual_no' | 'msisdn'
|
||||||
|
type DeviceSearchType = 'device_name' | 'virtual_no' | 'imei'
|
||||||
|
|
||||||
|
interface SearchTypeOption {
|
||||||
|
label : string
|
||||||
|
value : string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StandaloneCardsParams {
|
||||||
|
page : number
|
||||||
|
page_size : number
|
||||||
|
carrier_id ?: number
|
||||||
|
status ?: number
|
||||||
|
iccid ?: string
|
||||||
|
virtual_no ?: string
|
||||||
|
msisdn ?: string
|
||||||
|
shop_id ?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DevicesParams {
|
||||||
|
page : number
|
||||||
|
page_size : number
|
||||||
|
status ?: number
|
||||||
|
device_name ?: string
|
||||||
|
virtual_no ?: string
|
||||||
|
imei ?: string
|
||||||
|
shop_id ?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const cardSearchTypeOptions : SearchTypeOption[] = [
|
||||||
|
{ label: 'ICCID', value: 'iccid' },
|
||||||
|
{ label: '虚拟号', value: 'virtual_no' },
|
||||||
|
{ label: '接入号', value: 'msisdn' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const deviceSearchTypeOptions : SearchTypeOption[] = [
|
||||||
|
{ label: '设备号', value: 'device_name' },
|
||||||
|
{ label: '虚拟号', value: 'virtual_no' },
|
||||||
|
{ label: 'IMEI', value: 'imei' },
|
||||||
|
]
|
||||||
|
|
||||||
// 获取单卡列表(代理端)
|
// 获取单卡列表(代理端)
|
||||||
function getStandaloneCards(params : any) {
|
function getStandaloneCards(params : StandaloneCardsParams) {
|
||||||
return get<{ items : CardInfo[], page : number, size : number, total : number }>('/api/admin/iot-cards/standalone', { params })
|
return get<{ items : CardInfo[], page : number, size : number, total : number }>('/api/admin/iot-cards/standalone', { params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取设备列表(代理端)
|
// 获取设备列表(代理端)
|
||||||
function getDevices(params : any) {
|
function getDevices(params : DevicesParams) {
|
||||||
return get<{ items : DeviceInfo[], page : number, size : number, total : number }>('/api/admin/devices', { params })
|
return get<{ items : DeviceInfo[], page : number, size : number, total : number }>('/api/admin/devices', { params })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,13 +172,35 @@
|
|||||||
const carrierFilter = ref<number | undefined>(undefined)
|
const carrierFilter = ref<number | undefined>(undefined)
|
||||||
const statusFilter = ref<number | undefined>(undefined)
|
const statusFilter = ref<number | undefined>(undefined)
|
||||||
const selectedShopFilter = ref<SelectedShopFilter | null>(null)
|
const selectedShopFilter = ref<SelectedShopFilter | null>(null)
|
||||||
|
const cardSearchType = ref<CardSearchType>('iccid')
|
||||||
|
const deviceSearchType = ref<DeviceSearchType>('device_name')
|
||||||
const showCarrierPicker = ref(false)
|
const showCarrierPicker = ref(false)
|
||||||
|
const showSearchTypePicker = ref(false)
|
||||||
const showStatusPicker = ref(false)
|
const showStatusPicker = ref(false)
|
||||||
const showShopPicker = ref(false)
|
const showShopPicker = ref(false)
|
||||||
// 运营商列表
|
// 运营商列表
|
||||||
const carrierList = ref<CarrierInfo[]>([])
|
const carrierList = ref<CarrierInfo[]>([])
|
||||||
const isAgent = computed(() => userInfo.value?.user_type === 3)
|
const isAgent = computed(() => userInfo.value?.user_type === 3)
|
||||||
const searchPlaceholder = computed(() => activeTab.value === 'card' ? '搜索ICCID' : '搜索设备号')
|
const currentSearchType = computed(() => activeTab.value === 'card' ? cardSearchType.value : deviceSearchType.value)
|
||||||
|
const searchTypeOptions = computed(() => activeTab.value === 'card' ? cardSearchTypeOptions : deviceSearchTypeOptions)
|
||||||
|
const selectedSearchTypeLabel = computed(() => {
|
||||||
|
return searchTypeOptions.value.find(option => option.value === currentSearchType.value)?.label
|
||||||
|
|| (activeTab.value === 'card' ? 'ICCID' : '设备号')
|
||||||
|
})
|
||||||
|
const isDefaultSearchType = computed(() => {
|
||||||
|
return activeTab.value === 'card' ? cardSearchType.value === 'iccid' : deviceSearchType.value === 'device_name'
|
||||||
|
})
|
||||||
|
const searchPlaceholder = computed(() => {
|
||||||
|
if (activeTab.value === 'card') {
|
||||||
|
if (cardSearchType.value === 'virtual_no') return '搜索虚拟号'
|
||||||
|
if (cardSearchType.value === 'msisdn') return '搜索接入号'
|
||||||
|
return '搜索ICCID'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceSearchType.value === 'imei') return '搜索IMEI'
|
||||||
|
if (deviceSearchType.value === 'virtual_no') return '搜索虚拟号'
|
||||||
|
return '搜索设备号'
|
||||||
|
})
|
||||||
const canShowDeviceStopButton = computed(() => hasActionButtonPermission(ASSET_ACTION_BUTTON_CODES.deviceStop))
|
const canShowDeviceStopButton = computed(() => hasActionButtonPermission(ASSET_ACTION_BUTTON_CODES.deviceStop))
|
||||||
const canShowDeviceStartButton = computed(() => hasActionButtonPermission(ASSET_ACTION_BUTTON_CODES.deviceStart))
|
const canShowDeviceStartButton = computed(() => hasActionButtonPermission(ASSET_ACTION_BUTTON_CODES.deviceStart))
|
||||||
|
|
||||||
@@ -192,6 +255,34 @@
|
|||||||
: 'bg-[#fff7e6] text-[#d46b08]'
|
: 'bg-[#fff7e6] text-[#d46b08]'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyCardSearchKeyword(params : StandaloneCardsParams, keyword : string) {
|
||||||
|
if (cardSearchType.value === 'virtual_no') {
|
||||||
|
params.virtual_no = keyword
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardSearchType.value === 'msisdn') {
|
||||||
|
params.msisdn = keyword
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params.iccid = keyword
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyDeviceSearchKeyword(params : DevicesParams, keyword : string) {
|
||||||
|
if (deviceSearchType.value === 'imei') {
|
||||||
|
params.imei = keyword
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceSearchType.value === 'device_name') {
|
||||||
|
params.device_name = keyword
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params.virtual_no = keyword
|
||||||
|
}
|
||||||
|
|
||||||
// 合并后的资产列表
|
// 合并后的资产列表
|
||||||
const assetList = computed<AssetItem[]>(() => {
|
const assetList = computed<AssetItem[]>(() => {
|
||||||
const cards : AssetItem[] = cardList.value.map(card => ({
|
const cards : AssetItem[] = cardList.value.map(card => ({
|
||||||
@@ -259,7 +350,7 @@
|
|||||||
cardHasMore.value = true
|
cardHasMore.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const params : any = {
|
const params : StandaloneCardsParams = {
|
||||||
page: cardPage.value,
|
page: cardPage.value,
|
||||||
page_size: pageSize,
|
page_size: pageSize,
|
||||||
}
|
}
|
||||||
@@ -272,7 +363,7 @@
|
|||||||
params.status = statusFilter.value
|
params.status = statusFilter.value
|
||||||
}
|
}
|
||||||
if (searchKeyword.value.trim()) {
|
if (searchKeyword.value.trim()) {
|
||||||
params.iccid = searchKeyword.value.trim()
|
applyCardSearchKeyword(params, searchKeyword.value.trim())
|
||||||
}
|
}
|
||||||
if (userInfo.value?.user_type === 3 && selectedShopFilter.value) {
|
if (userInfo.value?.user_type === 3 && selectedShopFilter.value) {
|
||||||
params.shop_id = selectedShopFilter.value.id
|
params.shop_id = selectedShopFilter.value.id
|
||||||
@@ -326,13 +417,13 @@
|
|||||||
deviceHasMore.value = true
|
deviceHasMore.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const params : any = {
|
const params : DevicesParams = {
|
||||||
page: devicePage.value,
|
page: devicePage.value,
|
||||||
page_size: pageSize,
|
page_size: pageSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchKeyword.value.trim()) {
|
if (searchKeyword.value.trim()) {
|
||||||
params.virtual_no = searchKeyword.value.trim()
|
applyDeviceSearchKeyword(params, searchKeyword.value.trim())
|
||||||
}
|
}
|
||||||
if (statusFilter.value !== undefined) {
|
if (statusFilter.value !== undefined) {
|
||||||
params.status = statusFilter.value
|
params.status = statusFilter.value
|
||||||
@@ -416,6 +507,16 @@
|
|||||||
refreshList()
|
refreshList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onSearchTypeConfirm(option : SearchTypeOption) {
|
||||||
|
if (activeTab.value === 'card') {
|
||||||
|
cardSearchType.value = option.value as CardSearchType
|
||||||
|
} else {
|
||||||
|
deviceSearchType.value = option.value as DeviceSearchType
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshList()
|
||||||
|
}
|
||||||
|
|
||||||
// 获取当前选中的运营商名称
|
// 获取当前选中的运营商名称
|
||||||
const selectedCarrierName = computed(() => {
|
const selectedCarrierName = computed(() => {
|
||||||
if (carrierFilter.value === undefined) return '运营商'
|
if (carrierFilter.value === undefined) return '运营商'
|
||||||
@@ -661,6 +762,14 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="flex items-center gap-1.5 px-3 py-1.5 bg-[#f8fafc] rounded-full flex-shrink-0"
|
||||||
|
@click="showSearchTypePicker = true">
|
||||||
|
<text class="text-12px" :class="isDefaultSearchType ? 'text-[#64748b]' : 'text-brand font-medium'">
|
||||||
|
{{ selectedSearchTypeLabel }}
|
||||||
|
</text>
|
||||||
|
<i class="i-mdi-chevron-down text-12px text-[#94a3b8]" />
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="flex items-center gap-1.5 px-3 py-1.5 bg-[#f8fafc] rounded-full flex-shrink-0 max-w-36"
|
<view class="flex items-center gap-1.5 px-3 py-1.5 bg-[#f8fafc] rounded-full flex-shrink-0 max-w-36"
|
||||||
@click="showCarrierPicker = true">
|
@click="showCarrierPicker = true">
|
||||||
<text class="text-12px truncate"
|
<text class="text-12px truncate"
|
||||||
@@ -818,11 +927,18 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 运营商选择器 -->
|
<!-- 运营商选择器 -->
|
||||||
<SimplePicker v-model:show="showCarrierPicker" :options="carrierOptions" title="选择运营商"
|
<SimplePicker v-model:show="showCarrierPicker" :options="carrierOptions" :selected-value="carrierFilter"
|
||||||
|
auto-confirm title="选择运营商"
|
||||||
@confirm="onCarrierConfirm" />
|
@confirm="onCarrierConfirm" />
|
||||||
|
|
||||||
|
<!-- 搜索字段选择器 -->
|
||||||
|
<SimplePicker v-model:show="showSearchTypePicker" :options="searchTypeOptions" :selected-value="currentSearchType"
|
||||||
|
auto-confirm title="选择搜索字段"
|
||||||
|
@confirm="onSearchTypeConfirm" />
|
||||||
|
|
||||||
<!-- 状态选择器 -->
|
<!-- 状态选择器 -->
|
||||||
<SimplePicker v-model:show="showStatusPicker" :options="statusOptions" title="选择状态" @confirm="onStatusConfirm" />
|
<SimplePicker v-model:show="showStatusPicker" :options="statusOptions" :selected-value="statusFilter"
|
||||||
|
auto-confirm title="选择状态" @confirm="onStatusConfirm" />
|
||||||
|
|
||||||
<ShopCascadePicker v-model:show="showShopPicker" :selected-shop="selectedShopFilter" title="选择店铺"
|
<ShopCascadePicker v-model:show="showShopPicker" :selected-shop="selectedShopFilter" title="选择店铺"
|
||||||
@confirm="onShopConfirm" />
|
@confirm="onShopConfirm" />
|
||||||
|
|||||||
Reference in New Issue
Block a user