Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev

This commit is contained in:
leiqiaochu 2023-07-12 15:50:35 +08:00
commit 8e42e9e1d9
34 changed files with 216 additions and 188 deletions

View File

@ -50,9 +50,19 @@ export const regDomain = new RegExp(
); );
export const checkEndpoint = (_rule: Rule, value: string): Promise<any> => export const checkEndpoint = (_rule: Rule, value: string): Promise<any> =>
new Promise(async (resolve, reject) => { new Promise(async (resolve, reject) => {
if(!value) return resolve('');
const res: any = await validateField(value); const res: any = await validateField(value);
return res.result.passed ? resolve('') : reject(res.result.reason); return res.result.passed ? resolve('') : reject(res.result.reason);
}); });
export const checkHost = (_rule: Rule, value: string): Promise<any> =>
new Promise(async (resolve, reject) => {
if(!value) return resolve('');
if(!(regIP.test(value) || regIPv6.test(value) || regDomain.test(value))) {
return reject('请输入正确格式的Modbus主机IP地址')
}
return resolve('')
});
export const FormValidate = { export const FormValidate = {
name: [ name: [
{ required: true, message: '请输入名称', trigger: 'blur' }, { required: true, message: '请输入名称', trigger: 'blur' },
@ -65,8 +75,9 @@ export const FormValidate = {
message: '请输入Modbus主机IP', message: '请输入Modbus主机IP',
}, },
{ {
pattern: regIP || regIPv6 || regDomain, validator: checkHost,
message: '请输入正确格式的Modbus主机IP地址', trigger: 'blur',
// message: '请输入正确格式的Modbus主机IP地址',
}, },
], ],
port: [ port: [

View File

@ -73,7 +73,7 @@
</j-tooltip> </j-tooltip>
</div> </div>
</j-col> </j-col>
<j-col :span="12"> <!-- <j-col :span="12">
<div class="card-item-content-text"> <div class="card-item-content-text">
地址 地址
</div> </div>
@ -98,6 +98,14 @@
> >
</j-tooltip> </j-tooltip>
</div> </div>
</j-col> -->
<j-col :span="12">
<div class="card-item-content-text">
说明
</div>
<div class="card-item-content-text">
<j-ellipsis>{{slotProps.description}}</j-ellipsis>
</div>
</j-col> </j-col>
</j-row> </j-row>
</div> </div>

View File

@ -123,7 +123,7 @@
placeholder="请选择功能" placeholder="请选择功能"
v-model:value="modelRef.message.functionId" v-model:value="modelRef.message.functionId"
show-search show-search
@change="funcChange" @change="(e) => funcChange(e)"
> >
<j-select-option <j-select-option
v-for="i in metadata?.functions || []" v-for="i in metadata?.functions || []"
@ -216,12 +216,33 @@ const onPropertyChange = (val: string, flag?: boolean) => {
}; };
const onTypeChange = () => { const onTypeChange = () => {
modelRef.message = { // ,
properties: undefined, // modelRef.message = {
functionId: undefined, // properties: undefined,
inputs: [], // functionId: undefined,
value: undefined, // inputs: [],
}; // value: undefined,
// };
};
const funcChange = (val: string, _inputs?: any[]) => {
if (val) {
const arr =
props.metadata?.functions.find((item: any) => item.id === val)
?.inputs || [];
const list = arr.map((item: any) => {
const _item = _inputs?.find(i => i.id === item.id)
return {
id: item.id,
name: item.name,
value: undefined,
valueType: item?.valueType?.type,
..._item,
required: item?.expands?.required
};
});
modelRef.message.inputs = list;
}
}; };
watch( watch(
@ -232,6 +253,9 @@ watch(
if (newVal?.message?.properties) { if (newVal?.message?.properties) {
onPropertyChange(newVal?.message?.properties, true); onPropertyChange(newVal?.message?.properties, true);
} }
if (newVal?.message?.functionId) {
funcChange(newVal?.message?.functionId, newVal?.message?.inputs);
}
} }
}, },
{ {
@ -239,24 +263,6 @@ watch(
}, },
); );
const funcChange = (val: string) => {
if (val) {
const arr =
props.metadata?.functions.find((item: any) => item.id === val)
?.inputs || [];
const list = arr.map((item: any) => {
return {
id: item.id,
name: item.name,
value: undefined,
valueType: item?.valueType?.type,
required: item?.expands?.required
};
});
modelRef.message.inputs = list;
}
};
const saveBtn = () => const saveBtn = () =>
new Promise((resolve) => { new Promise((resolve) => {
formRef.value formRef.value

View File

@ -4,9 +4,9 @@
<div style="display: flex; padding-bottom: 24px; margin-bottom: 24px; border-bottom: 1px solid #E4E7F6"> <div style="display: flex; padding-bottom: 24px; margin-bottom: 24px; border-bottom: 1px solid #E4E7F6">
<j-avatar :size="100" :src="userInfos.avatar"></j-avatar> <j-avatar :size="100" :src="userInfos.avatar"></j-avatar>
<div style="margin-left: 24px;"> <div style="margin-left: 24px;">
<div class="name">{{ userInfos.name }}</div> <div class="name"><j-ellipsis>{{ userInfos.name }}</j-ellipsis></div>
<div class="subTitle">用户名: {{ userInfos?.username }}</div> <div class="subTitle"><j-ellipsis>用户名: {{ userInfos?.username }}</j-ellipsis></div>
<div class="subTitle">账号ID: {{ userInfos?.id }}</div> <!-- <div class="subTitle">账号ID: {{ userInfos?.id }}</div> -->
</div> </div>
</div> </div>
<j-descriptions <j-descriptions
@ -69,10 +69,10 @@ const org = computed(() => {
color: #1D2129; color: #1D2129;
font-weight: 500; font-weight: 500;
font-size: 26px; font-size: 26px;
margin: 15px 0 10px 0;
} }
.subTitle { .subTitle {
color: rgba(0, 0, 0, 0.6); color: rgba(0, 0, 0, 0.6);
margin-top: 5px;
} }
</style> </style>

View File

@ -72,7 +72,7 @@ const queryChartsAggList = async () => {
{ {
property: prop.data.id, property: prop.data.id,
alias: prop.data.id, alias: prop.data.id,
agg: agg.value, agg: _type.value ? agg.value : 'COUNT',
}, },
], ],
query: { query: {

View File

@ -43,7 +43,7 @@
> >
<template #bodyCell="{column, record}"> <template #bodyCell="{column, record}">
<span v-if="column.dataIndex === 'value'"> <span v-if="column.dataIndex === 'value'">
{{ record.range === 'true' ? record.value?.join('-') : record.value }} {{ record.range === true ? record.value?.join('-') : record.value }}
</span> </span>
</template> </template>
</j-table> </j-table>

View File

@ -8,10 +8,10 @@
ref="tableRef" ref="tableRef"
> >
<template #range="{data}"> <template #range="{data}">
{{ data.record.range === 'true' ? '范围值' : '固定值'}} {{ data.record.range === true ? '范围值' : '固定值'}}
</template> </template>
<template #value="{data}"> <template #value="{data}">
{{ data.record.range === 'true' ? data.record.value?.join('-') : data.record.value }} {{ data.record.range === true ? data.record.value?.join('-') : data.record.value }}
</template> </template>
<template #action="{data}"> <template #action="{data}">
<j-button <j-button
@ -92,9 +92,9 @@ const newColumns = computed(() => {
components: { components: {
props: { props: {
trueText: '范围值', trueText: '范围值',
trueValue: 'true', trueValue: true,
falseText: '固定值', falseText: '固定值',
falseValue: 'false', falseValue: false,
} }
} }
}) })

View File

@ -59,26 +59,26 @@ const formData = reactive<{
value: ValueType; value: ValueType;
rangeValue: ValueType; rangeValue: ValueType;
}>({ }>({
value: props.value.range === 'false' ? props.value.value : undefined, value: props.value?.range === false ? props.value?.value : undefined,
rangeValue: props.value.range === 'true' rangeValue: props.value?.range === true
? props.value.value || [undefined, undefined] ? props.value?.value || [undefined, undefined]
: [undefined, undefined], : [undefined, undefined],
}); });
const formRef = ref() const formRef = ref()
const showText = computed(() => { const showText = computed(() => {
if (props.value.range === 'false') { if (props.value.range === false) {
return props.value.value || '' return props.value?.value || ''
} else { } else {
return props.value.value?.[0] ? props.value.value.join('-') : '' return props.value?.value?.[0] ? props.value.value.join('-') : ''
} }
}) })
const confirm = () => { const confirm = () => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
formRef.value.validate().then(() => { formRef.value.validate().then(() => {
const value = props.value.range === 'true' ? formData.rangeValue : formData.value const value = props.value.range === true ? formData.rangeValue : formData.value
emit('update:value', { emit('update:value', {
...props.value, ...props.value,
value: value value: value
@ -93,7 +93,7 @@ const confirm = () => {
watch(() => props.value.range,(value, oldValue) => { watch(() => props.value.range,(value, oldValue) => {
if (value !== oldValue ) { if (value !== oldValue ) {
if (value === 'false') { if (value === false) {
formData.value = undefined formData.value = undefined
} else { } else {
formData.rangeValue = [undefined, undefined] formData.rangeValue = [undefined, undefined]

View File

@ -35,6 +35,7 @@ const useMetadata = (type: 'device' | 'product', key?: MetadataType, ): {
const productMetadata: any = JSON.parse(instanceStore.current.productMetadata) const productMetadata: any = JSON.parse(instanceStore.current.productMetadata)
const metaArray = key ? productMetadata[key] : [] const metaArray = key ? productMetadata[key] : []
const productIndexKeys = metaArray?.map((item:any, index: number) => index) || [] const productIndexKeys = metaArray?.map((item:any, index: number) => index) || []
productNoEdit.value.ids = metaArray?.map((item: any) => item.id) || []
productNoEdit.value.id = productIndexKeys productNoEdit.value.id = productIndexKeys
productNoEdit.value.name = productIndexKeys productNoEdit.value.name = productIndexKeys
if (key === 'properties') { if (key === 'properties') {

View File

@ -1,19 +1,19 @@
<template> <template>
<div class='device-detail-metadata' style="position: relative;"> <div class='device-detail-metadata' style="position: relative;">
<div class="tips"> <!-- <div class="tips">-->
<j-tooltip :title="instanceStore.detail?.independentMetadata && type === 'device' <!-- <j-tooltip :title="instanceStore.detail?.independentMetadata && type === 'device'-->
? '该设备已脱离产品物模型,修改产品物模型对该设备无影响' <!-- ? '该设备已脱离产品物模型,修改产品物模型对该设备无影响'-->
: '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型'"> <!-- : '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型'">-->
<div class="ellipsis" style='color: #999;'> <!-- <div class="ellipsis" style='color: #999;'>-->
<AIcon type="InfoCircleOutlined" style="margin-right: 3px" /> <!-- <AIcon type="InfoCircleOutlined" style="margin-right: 3px" />-->
{{ <!-- {{-->
instanceStore.detail?.independentMetadata && type === 'device' <!-- instanceStore.detail?.independentMetadata && type === 'device'-->
? '该设备已脱离产品物模型,修改产品物模型对该设备无影响' <!-- ? '该设备已脱离产品物模型,修改产品物模型对该设备无影响'-->
: '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型' <!-- : '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型'-->
}} <!-- }}-->
</div> <!-- </div>-->
</j-tooltip> <!-- </j-tooltip>-->
</div> <!-- </div>-->
<j-tabs class="metadataNav" destroyInactiveTabPane type="card"> <j-tabs class="metadataNav" destroyInactiveTabPane type="card">
<template #rightExtra> <template #rightExtra>
<j-space> <j-space>

View File

@ -2,10 +2,16 @@ import { saveProductMetadata } from "@/api/device/product";
import { saveMetadata } from "@/api/device/instance"; import { saveMetadata } from "@/api/device/instance";
import type { DeviceInstance } from "../../Instance/typings"; import type { DeviceInstance } from "../../Instance/typings";
import type { DeviceMetadata, MetadataItem, MetadataType, ProductItem } from "../../Product/typings"; import type { DeviceMetadata, MetadataItem, MetadataType, ProductItem } from "../../Product/typings";
import { differenceBy } from "lodash-es";
const filterProductMetadata = (data: any[], productMetaData: any[]) => {
const ids = productMetaData.map((item: any) => item.id)
const idsSet = new Set(ids)
return data.filter((a) => !idsSet.has(a.id))
}
/** /**
* *
* @param type events * @param type "events" | "functions" | "properties" | "tags"
* @param item {a},{b},{c} * @param item {a},{b},{c}
// * @param target product、device // * @param target product、device
* @param data product device [{event:[1,2,3]] * @param data product device [{event:[1,2,3]]
@ -21,25 +27,29 @@ import type { DeviceMetadata, MetadataItem, MetadataType, ProductItem } from "..
): ProductItem | DeviceInstance => { ): ProductItem | DeviceInstance => {
if (!data) return data; if (!data) return data;
const metadata = JSON.parse(data.metadata || '{}') as DeviceMetadata; const metadata = JSON.parse(data.metadata || '{}') as DeviceMetadata;
const config = (metadata[type] || []) as MetadataItem[]; let productMetaData
if (item.length > 0) {
item.forEach((i) => { if ((data as DeviceInstance).productMetadata) {
const index = config.findIndex((c) => c.id === i.id); productMetaData = JSON.parse((data as DeviceInstance).productMetadata)
if (index > -1) {
config[index] = i;
// onEvent?.('update', i);
} else {
config.push(i);
// onEvent?.('add', i);
}
});
} else {
console.warn('未触发物模型修改');
} }
console.log('updateMetadata', config, type)
// @ts-ignore if (productMetaData) {
// metadata[type] = config.sort((a, b) => b?.sortsIndex - a?.sortsIndex); if (productMetaData.properties && productMetaData.properties.length) {
metadata[type] = item.sort((a, b) => b?.sortsIndex - a?.sortsIndex); metadata.properties = filterProductMetadata(metadata.properties, productMetaData.properties)
}
if (productMetaData.functions && productMetaData.functions.length) {
metadata.functions = filterProductMetadata(metadata.functions, productMetaData.functions)
}
if (productMetaData.events && productMetaData.events.length) {
metadata.events = filterProductMetadata(metadata.events, productMetaData.events)
}
if (productMetaData.tags && productMetaData.tags.length) {
metadata.tags = filterProductMetadata(metadata.tags, productMetaData.tags)
}
}
console.log(metadata)
metadata[type] = metadata[type].sort((a, b) => b?.sortsIndex - a?.sortsIndex) as any[]
console.log('updateMetadata',metadata) console.log('updateMetadata',metadata)
data.metadata = JSON.stringify(metadata); data.metadata = JSON.stringify(metadata);
onEvent?.(data.metadata) onEvent?.(data.metadata)

View File

@ -31,9 +31,6 @@
selectedRowKeys: _selectedRowKeys, selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange, onChange: onSelectChange,
}" }"
:pagination="{
showSizeChanger: true,
}"
> >
<template #state="slotProps"> <template #state="slotProps">
<j-badge <j-badge

View File

@ -11,13 +11,8 @@
:request='queryUnbounded' :request='queryUnbounded'
model='TABLE' model='TABLE'
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'createTime', order: 'desc' }],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
:rowSelection="{ :rowSelection="{
type: 'radio', type: 'radio',
selectedRowKeys: _selectedRowKeys, selectedRowKeys: _selectedRowKeys,

View File

@ -9,13 +9,8 @@
:request="queryRechargeList" :request="queryRechargeList"
model="TABLE" model="TABLE"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'createTime', order: 'desc' }],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
:params="params" :params="params"
> >
<template #headerTitle> <template #headerTitle>

View File

@ -12,13 +12,8 @@
:columns="columns" :columns="columns"
:request="queryList" :request="queryList"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'time', order: 'desc' }], sorts: [{ name: 'time', order: 'desc' }],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
:params="params" :params="params"
:model="'TABLE'" :model="'TABLE'"
> >

View File

@ -10,7 +10,11 @@
@cancel="_vis = false" @cancel="_vis = false"
:confirmLoading="loading" :confirmLoading="loading"
> >
<pro-search :columns="columns" target="media-bind" @search="handleSearch" /> <pro-search
:columns="columns"
target="media-bind"
@search="handleSearch"
/>
<JProTable <JProTable
ref="listRef" ref="listRef"
@ -18,7 +22,7 @@
:columns="columns" :columns="columns"
:request="CascadeApi.queryChannelList" :request="CascadeApi.queryChannelList"
:defaultParams="{ :defaultParams="{
sorts: [{ name: 'name', order: 'desc' }], sorts: [{ name: 'deviceName', order: 'asc' }, { name: 'name', order: 'asc' }],
terms: [ terms: [
{ {
column: 'id', column: 'id',
@ -37,10 +41,9 @@
:params="params" :params="params"
:rowSelection="{ :rowSelection="{
selectedRowKeys: _selectedRowKeys, selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange, onSelectNone: onSelectNone,
}" onSelect: onSelect,
:pagination="{ onSelectAll: onAllSelect,
showSizeChanger: true,
}" }"
> >
<template #headerTitle> <template #headerTitle>
@ -101,6 +104,7 @@ const columns = [
title: '设备名称', title: '设备名称',
dataIndex: 'deviceName', dataIndex: 'deviceName',
key: 'deviceName', key: 'deviceName',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -109,6 +113,7 @@ const columns = [
title: '通道名称', title: '通道名称',
dataIndex: 'name', dataIndex: 'name',
key: 'name', key: 'name',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
first: true, first: true,
@ -118,6 +123,7 @@ const columns = [
title: '安装地址', title: '安装地址',
dataIndex: 'address', dataIndex: 'address',
key: 'address', key: 'address',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -126,6 +132,7 @@ const columns = [
title: '厂商', title: '厂商',
dataIndex: 'manufacturer', dataIndex: 'manufacturer',
key: 'manufacturer', key: 'manufacturer',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -135,6 +142,7 @@ const columns = [
dataIndex: 'status', dataIndex: 'status',
key: 'status', key: 'status',
scopedSlots: true, scopedSlots: true,
width: 150,
search: { search: {
type: 'select', type: 'select',
options: [ options: [
@ -161,8 +169,31 @@ const handleSearch = (e: any) => {
const listRef = ref(); const listRef = ref();
const _selectedRowKeys = ref<string[]>([]); const _selectedRowKeys = ref<string[]>([]);
const onSelectChange = (keys: string[]) => { const onSelectNone = () => {
_selectedRowKeys.value = [...keys]; _selectedRowKeys.value = [];
};
const onSelect = (record: any, selected: boolean) => {
const _set = new Set([..._selectedRowKeys.value])
if (selected) {
_set.add(record.id)
} else {
_set.delete(record.id)
}
_selectedRowKeys.value = [..._set]
};
const onAllSelect = (selected: boolean, _: any, keys: any[]) => {
const _keys = keys.map(item => item.id) || []
const _set = new Set([..._selectedRowKeys.value])
_keys.map((i: any) => {
if(selected) {
_set.add(i)
} else {
_set.delete(i)
}
});
_selectedRowKeys.value = [..._set]
}; };
const loading = ref(false); const loading = ref(false);

View File

@ -9,7 +9,6 @@
:columns="columns" :columns="columns"
:request="(e:any) => CascadeApi.queryBindChannel(route?.query.id as string, e)" :request="(e:any) => CascadeApi.queryBindChannel(route?.query.id as string, e)"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'name', order: 'desc' }], sorts: [{ name: 'name', order: 'desc' }],
}" }"
:params="params" :params="params"
@ -17,10 +16,6 @@
selectedRowKeys: _selectedRowKeys, selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange, onChange: onSelectChange,
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
> >
<template #headerTitle> <template #headerTitle>
<h3>通道列表</h3> <h3>通道列表</h3>
@ -168,6 +163,7 @@ const columns = [
key: 'deviceName', key: 'deviceName',
// width: 200, // width: 200,
// fixed: 'left', // fixed: 'left',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -175,6 +171,7 @@ const columns = [
{ {
title: '通道名称', title: '通道名称',
dataIndex: 'name', dataIndex: 'name',
ellipsis: true,
key: 'name', key: 'name',
search: { search: {
type: 'string', type: 'string',
@ -185,6 +182,7 @@ const columns = [
title: '国标ID', title: '国标ID',
dataIndex: 'channelId', dataIndex: 'channelId',
key: 'channelId', key: 'channelId',
ellipsis: true,
scopedSlots: true, scopedSlots: true,
headerCell: 'gbChannelIdHeader', // headerCell: 'gbChannelIdHeader', //
search: { search: {
@ -195,6 +193,7 @@ const columns = [
title: '安装地址', title: '安装地址',
dataIndex: 'address', dataIndex: 'address',
key: 'address', key: 'address',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -203,6 +202,7 @@ const columns = [
title: '厂商', title: '厂商',
dataIndex: 'manufacturer', dataIndex: 'manufacturer',
key: 'manufacturer', key: 'manufacturer',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -212,6 +212,7 @@ const columns = [
dataIndex: 'status', dataIndex: 'status',
key: 'status', key: 'status',
scopedSlots: true, scopedSlots: true,
width: 150,
search: { search: {
type: 'select', type: 'select',
options: [ options: [
@ -226,6 +227,7 @@ const columns = [
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 100,
scopedSlots: true, scopedSlots: true,
}, },
]; ];

View File

@ -428,6 +428,10 @@
required: true, required: true,
message: '请输入心跳周期', message: '请输入心跳周期',
}, },
{
pattern: /^[1-9]\d*$/,
message: '请输入1~10000的整数',
}
]" ]"
> >
<j-input-number <j-input-number
@ -450,6 +454,10 @@
required: true, required: true,
message: '请输入注册间隔', message: '请输入注册间隔',
}, },
{
pattern: /^[1-9]\d*$/,
message: '请输入1~10000的整数',
}
]" ]"
> >
<j-input-number <j-input-number

View File

@ -56,16 +56,20 @@
{{ slotProps.name }} {{ slotProps.name }}
</h3> </h3>
<p>通道数量{{ slotProps.count || 0 }}</p> <p>通道数量{{ slotProps.count || 0 }}</p>
<Ellipsis> <j-badge
<j-badge :status="
:text="`sip:${slotProps.sipConfigs[0]?.sipId}@${slotProps.sipConfigs[0]?.hostAndPort}`" slotProps.status?.value === 'enabled'
:status=" ? 'success'
slotProps.status?.value === 'enabled' : 'error'
? 'success' "
: 'error' style="display: flex; align-items: center;"
" >
/> <template #text>
</Ellipsis> <j-ellipsis>
{{ `sip:${slotProps.sipConfigs[0]?.sipId}@${slotProps.sipConfigs[0]?.hostAndPort}` }}
</j-ellipsis>
</template>
</j-badge>
</template> </template>
<template #actions="item"> <template #actions="item">
<PermissionButton <PermissionButton
@ -170,6 +174,7 @@ const columns = [
key: 'name', key: 'name',
width: 200, width: 200,
fixed: 'left', fixed: 'left',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -179,12 +184,14 @@ const columns = [
dataIndex: 'sipId', dataIndex: 'sipId',
key: 'sipId', key: 'sipId',
scopedSlots: true, scopedSlots: true,
ellipsis: true,
}, },
{ {
title: '上级SIP 地址', title: '上级SIP 地址',
dataIndex: 'publicHost', dataIndex: 'publicHost',
key: 'publicHost', key: 'publicHost',
scopedSlots: true, scopedSlots: true,
ellipsis: true,
}, },
{ {
title: '通道数量', title: '通道数量',

View File

@ -65,7 +65,7 @@ const createChart = () => {
left: maxY > 100000 ? 90 : 50, left: maxY > 100000 ? 90 : 50,
right: '5%', right: '5%',
top: '5%', top: '5%',
bottom: '5%', bottom: '10%',
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
@ -199,7 +199,7 @@ watch(
.chart, .chart,
.no-data { .no-data {
width: 100%; width: 100%;
min-height: calc(100vh - 430px); min-height: calc(100vh - 450px);
} }
.no-data { .no-data {
display: flex; display: flex;

View File

@ -35,11 +35,13 @@
/> />
</j-col> </j-col>
<j-col :span="24" class="dash-board-bottom"> <j-col :span="24" class="dash-board-bottom">
<Card <full-page>
title="播放数量(人次)" <Card
:chartData="chartData" title="播放数量(人次)"
@change="getPlayCount" :chartData="chartData"
/> @change="getPlayCount"
/>
</full-page>
</j-col> </j-col>
</j-row> </j-row>
</page-container> </page-container>

View File

@ -302,8 +302,8 @@ const handleSubmit = () => {
}; };
} }
const res = formData.value.id const res = formData.value.id
? await ChannelApi.update(formData.value.id, extraFormData) ? await ChannelApi.update(formData.value.id, extraFormData).finally(() => {loading.value = false;})
: await ChannelApi.save(extraFormData); : await ChannelApi.save(extraFormData).finally(() => {loading.value = false;});
if (res.success) { if (res.success) {
onlyMessage('操作成功'); onlyMessage('操作成功');
_vis.value = false; _vis.value = false;

View File

@ -34,9 +34,6 @@
sorts: [{ name: 'modifyTime', order: 'desc' }], sorts: [{ name: 'modifyTime', order: 'desc' }],
}" }"
:params="params" :params="params"
:pagination="{
showSizeChanger: true,
}"
> >
<template #headerTitle> <template #headerTitle>
<j-tooltip <j-tooltip
@ -156,6 +153,7 @@ const columns = [
title: '通道ID', title: '通道ID',
dataIndex: 'channelId', dataIndex: 'channelId',
key: 'channelId', key: 'channelId',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -164,6 +162,7 @@ const columns = [
title: '名称', title: '名称',
dataIndex: 'name', dataIndex: 'name',
key: 'name', key: 'name',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
first: true, first: true,
@ -173,6 +172,7 @@ const columns = [
title: '厂商', title: '厂商',
dataIndex: 'manufacturer', dataIndex: 'manufacturer',
key: 'manufacturer', key: 'manufacturer',
ellipsis: true,
search: { search: {
type: 'string', type: 'string',
}, },
@ -180,6 +180,7 @@ const columns = [
{ {
title: '安装地址', title: '安装地址',
dataIndex: 'address', dataIndex: 'address',
ellipsis: true,
key: 'address', key: 'address',
search: { search: {
type: 'string', type: 'string',
@ -190,6 +191,7 @@ const columns = [
dataIndex: 'status', dataIndex: 'status',
key: 'status', key: 'status',
scopedSlots: true, scopedSlots: true,
width: 150,
search: { search: {
type: 'select', type: 'select',
options: [ options: [
@ -204,6 +206,7 @@ const columns = [
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 200,
scopedSlots: true, scopedSlots: true,
}, },
]; ];

View File

@ -57,9 +57,6 @@
} }
}" }"
:alertRender="false" :alertRender="false"
:pagination="{
showSizeChanger: true,
}"
> >
<template #channelNumber="slotProps"> <template #channelNumber="slotProps">
<span>{{ slotProps.channelNumber || 0 }}</span> <span>{{ slotProps.channelNumber || 0 }}</span>

View File

@ -9,14 +9,10 @@
:columns="columns" :columns="columns"
:request="(e:any) => templateApi.getHistory(e, data.id)" :request="(e:any) => templateApi.getHistory(e, data.id)"
:defaultParams="{ :defaultParams="{
pageSize: 5,
sorts: [{ name: 'notifyTime', order: 'desc' }], sorts: [{ name: 'notifyTime', order: 'desc' }],
terms: [{ column: 'notifyType$IN', value: data.type }], terms: [{ column: 'notifyType$IN', value: data.type }],
}" }"
:params="params" :params="params"
:pagination="{
pageSizeOptions: ['5', '10', '20', '50', '100'],
}"
> >
<template #notifyTime="slotProps"> <template #notifyTime="slotProps">
{{ moment(slotProps.notifyTime).format('YYYY-MM-DD HH:mm:ss') }} {{ moment(slotProps.notifyTime).format('YYYY-MM-DD HH:mm:ss') }}

View File

@ -14,13 +14,8 @@
model="TABLE" model="TABLE"
:params="queryParams" :params="queryParams"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'createTime', order: 'desc' }],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
> >
<template #headerTitle> <template #headerTitle>
<PermissionButton <PermissionButton

View File

@ -29,13 +29,8 @@
}" }"
model="TABLE" model="TABLE"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'createTime', order: 'desc' }],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
/> />
</div> </div>
</j-modal> </j-modal>

View File

@ -17,13 +17,6 @@
onChange: table.onSelectChange, onChange: table.onSelectChange,
}" }"
model="TABLE" model="TABLE"
:defaultParams="{
pageSize: 10,
}"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
> >
<template #headerTitle> <template #headerTitle>
<PermissionButton <PermissionButton

View File

@ -261,7 +261,7 @@ const table = reactive({
const pager = reactive({ const pager = reactive({
current: 1, current: 1,
pageSize: 10, pageSize: 12,
total: table.data.length, total: table.data.length,
}); });
const pageArr = computed(() => { const pageArr = computed(() => {

View File

@ -14,13 +14,8 @@
model="TABLE" model="TABLE"
:params="queryParams" :params="queryParams"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'id', order: 'asc' }], sorts: [{ name: 'id', order: 'asc' }],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
> >
<template #headerTitle> <template #headerTitle>
<PermissionButton <PermissionButton

View File

@ -3,12 +3,11 @@
<div class="table"> <div class="table">
<j-pro-table <j-pro-table
:columns="columns" :columns="columns"
:dataSource="props.tableData" :dataSource="_tableData"
:rowSelection="props.mode !== 'home' ? rowSelection : undefined" :rowSelection="props.mode !== 'home' ? rowSelection : undefined"
noPagination noPagination
model="TABLE" model="TABLE"
> >
<!-- :rowKey="(record) => record.id + record.method" -->
<template #url="slotProps"> <template #url="slotProps">
<span <span
style="color: #1d39c4; cursor: pointer" style="color: #1d39c4; cursor: pointer"
@ -39,6 +38,7 @@ import {
import { modeType } from '../typing'; import { modeType } from '../typing';
import { useDepartmentStore } from '@/store/department'; import { useDepartmentStore } from '@/store/department';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { uniqBy } from 'lodash-es';
const department = useDepartmentStore(); const department = useDepartmentStore();
const emits = defineEmits([ const emits = defineEmits([
@ -70,8 +70,8 @@ const columns = [
}, },
]; ];
watchEffect(() => { const _tableData = computed(() => {
console.log(props.tableData) return uniqBy(props.tableData, 'id') || []
}) })
const rowSelection = { const rowSelection = {
@ -91,9 +91,10 @@ const rowSelection = {
// }); // });
// } // }
// }, // },
onChange: (keys: string[]) => { onChange: (keys: string[], _data: any[]) => {
const _keys = _data.map(i => i.id)
// id // id
const currenTableKeys = props.tableData.map((m: any) => m.id); const currenTableKeys = _tableData.value.map((m: any) => m.id);
// , id // , id
const oldSelectedKeys = currenTableKeys.filter((key) => const oldSelectedKeys = currenTableKeys.filter((key) =>
props.sourceKeys.includes(key), props.sourceKeys.includes(key),
@ -104,16 +105,16 @@ const rowSelection = {
); );
// //
const removeKeys = oldSelectedKeys.filter((key) => !keys.includes(key)); const removeKeys = oldSelectedKeys.filter((key) => !_keys.includes(key));
// //
const addKeys = keys.filter((key) => !oldSelectedKeys.includes(key)); const addKeys = _keys.filter((key) => !oldSelectedKeys.includes(key));
// //
emits('update:selectedRowKeys', [...otherSelectedKeys, ...keys]); emits('update:selectedRowKeys', [...otherSelectedKeys, ..._keys]);
// / // /
const changed = {}; const changed = {};
[...addKeys, ...removeKeys].forEach((key: string) => { [...addKeys, ...removeKeys].forEach((key: string) => {
changed[key] = props.tableData.find((f: any) => f.id === key); changed[key] = _tableData.value.find((f: any) => f.id === key);
}); });
if (props.mode === 'appManger') { if (props.mode === 'appManger') {
// //
@ -178,7 +179,7 @@ watch(
() => props.selectedRowKeys, () => props.selectedRowKeys,
(n) => { (n) => {
// console.log('props.selectedRowKeys: ', n); // console.log('props.selectedRowKeys: ', n);
rowSelection.selectedRowKeys.value = n; rowSelection.selectedRowKeys.value = n
}, },
); );
</script> </script>

View File

@ -14,13 +14,8 @@
model="TABLE" model="TABLE"
:params="queryParams" :params="queryParams"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'createTime', order: 'desc' }],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
> >
<template #headerTitle> <template #headerTitle>
<PermissionButton <PermissionButton

View File

@ -14,16 +14,11 @@
model="TABLE" model="TABLE"
:params="queryParams" :params="queryParams"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [ sorts: [
{ name: 'createTime', order: 'desc' }, { name: 'createTime', order: 'desc' },
{ name: 'id', order: 'desc' }, { name: 'id', order: 'desc' },
], ],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
> >
<template #headerTitle> <template #headerTitle>
<PermissionButton <PermissionButton

View File

@ -14,13 +14,8 @@
model="TABLE" model="TABLE"
:params="queryParams" :params="queryParams"
:defaultParams="{ :defaultParams="{
pageSize: 10,
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'createTime', order: 'desc' }],
}" }"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
> >
<template #headerTitle> <template #headerTitle>
<PermissionButton <PermissionButton