Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
ee323a1a7d
|
@ -571,3 +571,6 @@ export const queryLog = (deviceId: string, data: Record<string, unknown>) => ser
|
|||
*/
|
||||
export const queryLogsType = () => server.get(`/dictionary/device-log-type/items`)
|
||||
|
||||
export const getDeviceNumber = (data?:any) => server.post<number>('/device-instance/_count', data)
|
||||
|
||||
|
||||
|
|
|
@ -107,8 +107,10 @@ const read = (type: string, data: any) => {
|
|||
const getList = () => {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
'sorts[0].name': 'notifyTime',
|
||||
'sorts[0].order': 'desc',
|
||||
sorts: [{
|
||||
name: 'notifyTime',
|
||||
order: 'desc'
|
||||
}],
|
||||
terms: [
|
||||
{
|
||||
terms: [
|
||||
|
|
|
@ -40,14 +40,13 @@
|
|||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { TOKEN_KEY } from '@/utils/variable';
|
||||
import { LocalStore, onlyMessage } from '@/utils/comm';
|
||||
import { downloadFile, downloadFileByUrl } from '@/utils/utils';
|
||||
import { downloadFileByUrl } from '@/utils/utils';
|
||||
import {
|
||||
deviceImport,
|
||||
deviceTemplateDownload,
|
||||
templateDownload,
|
||||
} from '@/api/device/instance';
|
||||
import { EventSourcePolyfill } from 'event-source-polyfill';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
|
||||
type Emits = {
|
||||
(e: 'update:modelValue', data: string[]): void;
|
||||
|
@ -73,6 +72,15 @@ const props = defineProps({
|
|||
};
|
||||
},
|
||||
},
|
||||
url: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
fileType: 'xlsx',
|
||||
autoDeploy: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const importLoading = ref<boolean>(false);
|
||||
|
@ -81,7 +89,6 @@ const count = ref<number>(0);
|
|||
const errMessage = ref<string>('');
|
||||
|
||||
const downFile = async (type: string) => {
|
||||
// downloadFile(deviceTemplateDownload(props.product, type));
|
||||
const res: any = await templateDownload(props.product, type);
|
||||
if (res) {
|
||||
const blob = new Blob([res], { type: type });
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
width="700px"
|
||||
@cancel="modalVis = false"
|
||||
@ok="handleItemModalSubmit"
|
||||
:zIndex='1100'
|
||||
>
|
||||
<div style="width: 100%; height: 300px">
|
||||
<JMonacoEditor v-model:modelValue="objectValue" />
|
||||
|
@ -157,15 +158,17 @@ const componentsType = ref<ITypes>({
|
|||
});
|
||||
const typeMap = new Map(Object.entries(componentsType.value));
|
||||
|
||||
const myValue = computed({
|
||||
get: () => {
|
||||
return props.modelValue;
|
||||
},
|
||||
set: (val: any) => {
|
||||
objectValue.value = val;
|
||||
emit('update:modelValue', val);
|
||||
},
|
||||
});
|
||||
// const myValue = computed({
|
||||
// get: () => {
|
||||
// return props.modelValue;
|
||||
// },
|
||||
// set: (val: any) => {
|
||||
// objectValue.value = val;
|
||||
// emit('update:modelValue', val);
|
||||
// },
|
||||
// });
|
||||
|
||||
const myValue = ref(props.modelValue)
|
||||
|
||||
// 代码编辑器弹窗
|
||||
const modalVis = ref<boolean>(false);
|
||||
|
@ -174,6 +177,7 @@ const handleItemModalSubmit = () => {
|
|||
myValue.value = objectValue.value.replace(/[\r\n]\s*/g, '');
|
||||
modalVis.value = false;
|
||||
emit('change', objectValue.value)
|
||||
emit('update:modelValue', myValue.value);
|
||||
};
|
||||
|
||||
// 文件上传
|
||||
|
@ -189,18 +193,28 @@ const handleFileChange = (info: UploadChangeParam<UploadFile<any>>) => {
|
|||
|
||||
const selectChange = (e: string, option: any) => {
|
||||
emit('change', e, option)
|
||||
emit('update:modelValue', myValue.value);
|
||||
}
|
||||
|
||||
const timeChange = (e: any) => {
|
||||
emit('change', e)
|
||||
emit('update:modelValue', myValue.value);
|
||||
}
|
||||
|
||||
const inputChange = (e: any) => {
|
||||
emit('change', e && e.target ? e.target.value : e)
|
||||
emit('update:modelValue', myValue.value);
|
||||
}
|
||||
|
||||
const dateChange = (e: any) => {
|
||||
emit('change', e)
|
||||
emit('update:modelValue', myValue.value);
|
||||
}
|
||||
|
||||
myValue.value = props.modelValue
|
||||
|
||||
if (props.itemType === 'object') {
|
||||
objectValue.value = props.modelValue as string
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -187,19 +187,14 @@
|
|||
<j-form-item
|
||||
label="采集频率"
|
||||
:name="['configuration', 'interval']"
|
||||
:rules="[
|
||||
...ModBusRules.interval,
|
||||
{
|
||||
validator: checkLength,
|
||||
trigger: 'change',
|
||||
},
|
||||
]"
|
||||
:rules="[...ModBusRules.interval]"
|
||||
>
|
||||
<j-input
|
||||
<j-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入采集频率"
|
||||
v-model:value="formData.configuration.interval"
|
||||
addon-after="ms"
|
||||
:max="9999999999999998"
|
||||
/>
|
||||
</j-form-item>
|
||||
|
||||
|
@ -346,15 +341,6 @@ const changeFunction = (value: string) => {
|
|||
value === 'InputRegisters' ? ['read'] : ['read', 'write'];
|
||||
};
|
||||
|
||||
const checkLength = (_rule: Rule, value: string): Promise<any> =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
if (value) {
|
||||
return String(value).length > 64
|
||||
? reject('最多可输入64个字符')
|
||||
: resolve('');
|
||||
}
|
||||
});
|
||||
|
||||
const checkProvider = (_rule: Rule, value: string): Promise<any> =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
if (value) {
|
||||
|
|
|
@ -49,19 +49,14 @@
|
|||
<j-form-item
|
||||
label="采集频率"
|
||||
:name="['configuration', 'interval']"
|
||||
:rules="[
|
||||
...OPCUARules.interval,
|
||||
{
|
||||
validator: checkLength,
|
||||
trigger: 'change',
|
||||
},
|
||||
]"
|
||||
:rules="[...OPCUARules.interval]"
|
||||
>
|
||||
<j-input
|
||||
<j-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入采集频率"
|
||||
v-model:value="formData.configuration.interval"
|
||||
addon-after="ms"
|
||||
:max="9999999999999998"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item label="" :name="['features']">
|
||||
|
@ -156,17 +151,6 @@ const handleCancel = () => {
|
|||
emit('change', false);
|
||||
};
|
||||
|
||||
const checkLength = (_rule: Rule, value: string): Promise<any> =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
if (value) {
|
||||
return String(value).length > 64
|
||||
? reject('最多可输入64个字符')
|
||||
: resolve('');
|
||||
} else {
|
||||
reject('');
|
||||
}
|
||||
});
|
||||
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
};
|
||||
|
|
|
@ -111,17 +111,13 @@
|
|||
'value',
|
||||
]"
|
||||
:rules="[
|
||||
{
|
||||
validator: checkLength,
|
||||
trigger: 'change',
|
||||
},
|
||||
{
|
||||
pattern: regOnlyNumber,
|
||||
message: '请输入0或者正整数',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<j-input
|
||||
<j-input-number
|
||||
style="width: 60%"
|
||||
v-model:value="
|
||||
record.configuration[dataIndex].value
|
||||
|
@ -129,12 +125,13 @@
|
|||
placeholder="请输入"
|
||||
allowClear
|
||||
addon-after="ms"
|
||||
:max="9999999999999998"
|
||||
:disabled="
|
||||
index !== 0 &&
|
||||
record.configuration[dataIndex].check
|
||||
"
|
||||
@blur="changeValue(index, dataIndex)"
|
||||
></j-input>
|
||||
></j-input-number>
|
||||
<j-checkbox
|
||||
style="margin-left: 5px; margin-top: 5px"
|
||||
v-show="index !== 0"
|
||||
|
|
|
@ -36,10 +36,6 @@
|
|||
pattern: regOnlyNumber,
|
||||
message: '请输入0或者正整数',
|
||||
},
|
||||
{
|
||||
validator: checkLength,
|
||||
trigger: 'change',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<template #label>
|
||||
|
@ -53,11 +49,12 @@
|
|||
</j-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<j-input
|
||||
<j-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入采集频率"
|
||||
v-model:value="formData.interval"
|
||||
addon-after="ms"
|
||||
:max="9999999999999998"
|
||||
/>
|
||||
</j-form-item>
|
||||
|
||||
|
|
|
@ -572,20 +572,20 @@ const handleClick = (dt: any) => {
|
|||
};
|
||||
|
||||
const subscribeProperty = (value: any) => {
|
||||
const list = value.map((item: any) => item.id);
|
||||
const id = `collector-${props.data?.channelId || 'channel'}-${
|
||||
props.data?.id || 'point'
|
||||
}-data-${list.join('-')}`;
|
||||
const topic = `/collector/${props.data?.channelId || '*'}/${
|
||||
props.data?.id || '*'
|
||||
}/data`;
|
||||
subRef.value = getWebSocket(id, topic, {
|
||||
pointId: list.join(','),
|
||||
})
|
||||
?.pipe(map((res: any) => res.payload))
|
||||
.subscribe((payload: any) => {
|
||||
propertyValue.value.set(payload.pointId, payload);
|
||||
});
|
||||
// const list = value.map((item: any) => item.id);
|
||||
// const id = `collector-${props.data?.channelId || 'channel'}-${
|
||||
// props.data?.id || 'point'
|
||||
// }-data-${list.join('-')}`;
|
||||
// const topic = `/collector/${props.data?.channelId || '*'}/${
|
||||
// props.data?.id || '*'
|
||||
// }/data`;
|
||||
// subRef.value = getWebSocket(id, topic, {
|
||||
// pointId: list.join(','),
|
||||
// })
|
||||
// ?.pipe(map((res: any) => res.payload))
|
||||
// .subscribe((payload: any) => {
|
||||
// propertyValue.value.set(payload.pointId, payload);
|
||||
// });
|
||||
};
|
||||
|
||||
const onCheckAllChange = (e: any) => {
|
||||
|
|
|
@ -237,7 +237,8 @@ const handleSearch = async (value: any) => {
|
|||
if (clickSearch) {
|
||||
defualtDataSource.value = res.result;
|
||||
if (res.result.length !== 0) {
|
||||
selectedKeys.value = [res.result[0].id]; // 通道跳转进来或者搜索时,默认选中第一个
|
||||
selectedKeys.value.length === 0 &&
|
||||
(selectedKeys.value = [res.result[0].id]); // 通道跳转进来或者搜索时,默认选中第一个
|
||||
}
|
||||
} else {
|
||||
defualtDataSource.value = _.cloneDeep(root);
|
||||
|
@ -285,7 +286,11 @@ watch(
|
|||
watch(
|
||||
() => searchValue.value,
|
||||
(value) => {
|
||||
!value && handleSearch(value);
|
||||
if (!value) {
|
||||
setTimeout(() => {
|
||||
handleSearch(value);
|
||||
}, 0);
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -30,7 +30,7 @@ const changeTree = (row: any) => {
|
|||
collectorId: row?.id,
|
||||
};
|
||||
spinning.value = false;
|
||||
}, 300);
|
||||
}, 1000);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ export const pointParams = (data: any) => {
|
|||
from: Number(data.time.time[0]),
|
||||
to: Number(data.time.time[1]),
|
||||
interval: getParams(data.time).interval,
|
||||
format: getParams(data.time).format,
|
||||
format: 'YYYY-MM-dd HH:mm',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getDeviceNumber } from '@/api/device/product';
|
||||
import { getDeviceNumber } from '@/api/device/instance';
|
||||
import { EventSourcePolyfill } from 'event-source-polyfill';
|
||||
|
||||
const emit = defineEmits(['close', 'save']);
|
||||
|
@ -36,6 +36,10 @@ const props = defineProps({
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
const count = ref<number>(0);
|
||||
|
@ -90,7 +94,7 @@ watch(
|
|||
() => props.api,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
getDeviceNumber({}).then(resp => {
|
||||
getDeviceNumber(props.data).then(resp => {
|
||||
if(resp.status === 200){
|
||||
total.value = resp.result
|
||||
getData(newValue);
|
||||
|
|
|
@ -268,6 +268,7 @@
|
|||
@close="operationVisible = false"
|
||||
:api="api"
|
||||
:type="type"
|
||||
:data="params"
|
||||
@save="onRefresh"
|
||||
/>
|
||||
<Save
|
||||
|
@ -575,7 +576,7 @@ onMounted(() => {
|
|||
const handleParams = (config: Record<string, any>) => {
|
||||
const _terms: Record<string, any> = {};
|
||||
paramsFormat(config, _terms);
|
||||
if (Object.keys(_terms._value).length && Object.keys(_terms).length) {
|
||||
if (Object.keys(_terms).length) {
|
||||
const url = new URLSearchParams();
|
||||
Object.keys(_terms).forEach((key) => {
|
||||
url.append(key, _terms[key]);
|
||||
|
@ -715,7 +716,7 @@ const activeAllDevice = () => {
|
|||
type.value = 'active';
|
||||
const activeAPI = `${BASE_API_PATH}/device-instance/deploy?:X_Access_Token=${LocalStore.get(
|
||||
TOKEN_KEY,
|
||||
)}&${handleParams(params)}`;
|
||||
)}&${handleParams(params.value)}`;
|
||||
api.value = activeAPI;
|
||||
operationVisible.value = true;
|
||||
};
|
||||
|
@ -724,7 +725,7 @@ const syncDeviceStatus = () => {
|
|||
type.value = 'sync';
|
||||
const syncAPI = `${BASE_API_PATH}/device-instance/state/_sync?:X_Access_Token=${LocalStore.get(
|
||||
TOKEN_KEY,
|
||||
)}&${handleParams(params)}`;
|
||||
)}&${handleParams(params.value)}`;
|
||||
api.value = syncAPI;
|
||||
operationVisible.value = true;
|
||||
};
|
||||
|
|
|
@ -478,12 +478,6 @@ export default {
|
|||
buttons: [
|
||||
{ id: 'view', name: '查看', enabled: true, granted: true },
|
||||
{ id: 'update', name: '编辑', enabled: true, granted: true },
|
||||
{
|
||||
id: 'action',
|
||||
name: '启/禁用',
|
||||
enabled: true,
|
||||
granted: true,
|
||||
},
|
||||
{ id: 'delete', name: '删除', enabled: true, granted: true },
|
||||
{
|
||||
id: 'add',
|
||||
|
@ -949,12 +943,6 @@ export default {
|
|||
buttons: [
|
||||
{ id: 'view', name: '查看', enabled: true, granted: true },
|
||||
{ id: 'update', name: '编辑', enabled: true, granted: true },
|
||||
{
|
||||
id: 'action',
|
||||
name: '启/禁用',
|
||||
enabled: true,
|
||||
granted: true,
|
||||
},
|
||||
{ id: 'delete', name: '删除', enabled: true, granted: true },
|
||||
{
|
||||
id: 'add',
|
||||
|
|
|
@ -2083,8 +2083,9 @@ export default [
|
|||
],
|
||||
},
|
||||
],
|
||||
accessSupport: { text: "不支持", value: "unsupported" },
|
||||
supportDataAccess: false
|
||||
accessSupport: { text: "支持", value: "support" },
|
||||
supportDataAccess: true,
|
||||
assetType: 'aliyunNorthOutput'
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
title="导入"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<div style="margin-top: 10px">
|
||||
<j-form :layout="'vertical'" :model="modelRef" ref="formRef" :rules="rules">
|
||||
<j-form
|
||||
:layout="'vertical'"
|
||||
:model="modelRef"
|
||||
ref="formRef"
|
||||
:rules="rules"
|
||||
>
|
||||
<j-form-item label="平台对接" required name="configId">
|
||||
<j-select
|
||||
showSearch
|
||||
|
@ -33,6 +37,14 @@
|
|||
</j-form-item>
|
||||
|
||||
<j-form-item label="文件上传" v-if="modelRef.configId">
|
||||
<UploadFile
|
||||
:product="modelRef.configId"
|
||||
v-model="modelRef.upload"
|
||||
:file="modelRef.fileType"
|
||||
/>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
<!-- <j-form-item label="文件上传" v-if="modelRef.configId">
|
||||
<j-upload
|
||||
v-model:fileList="modelRef.upload"
|
||||
name="file"
|
||||
|
@ -70,30 +82,30 @@
|
|||
<a-icon class="check-num" style="color: red" type="close" />
|
||||
失败 总数量
|
||||
<span class="check-num">{{ errCount }}</span>
|
||||
</div> -->
|
||||
</div>
|
||||
</j-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<j-button type="primary" @click="handleOk">关闭</j-button>
|
||||
</template>
|
||||
</j-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||
import { LocalStore } from '@/utils/comm';
|
||||
import { downloadFile, downloadFileByUrl } from '@/utils/utils';
|
||||
import { queryPlatformNoPage, _import ,exportCard} from '@/api/iot-card/cardManagement';
|
||||
// import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
|
||||
// import { downloadFile, downloadFileByUrl } from '@/utils/utils';
|
||||
import {
|
||||
queryPlatformNoPage,
|
||||
_import,
|
||||
} from '@/api/iot-card/cardManagement';
|
||||
import UploadFile from './UploadFile.vue'
|
||||
|
||||
const emit = defineEmits(['close', 'save']);
|
||||
|
||||
const configList = ref<Record<string, any>[]>([]);
|
||||
const loading = ref<boolean>(false);
|
||||
const totalCount = ref<number>(0);
|
||||
const errCount = ref<number>(0);
|
||||
const formRef = ref(null)
|
||||
const importStatus = ref(false)
|
||||
// const loading = ref<boolean>(false);
|
||||
// const totalCount = ref<number>(0);
|
||||
// const errCount = ref<number>(0);
|
||||
const formRef = ref(null);
|
||||
// const importStatus = ref(false);
|
||||
const modelRef = reactive({
|
||||
configId: undefined,
|
||||
upload: [],
|
||||
|
@ -101,8 +113,8 @@ const modelRef = reactive({
|
|||
});
|
||||
|
||||
const rules = {
|
||||
configId: [{ required: true, message: '请选择平台对接'}]
|
||||
}
|
||||
configId: [{ required: true, message: '请选择平台对接' }],
|
||||
};
|
||||
|
||||
const getConfig = async () => {
|
||||
const resp: any = await queryPlatformNoPage({
|
||||
|
@ -125,59 +137,53 @@ const getConfig = async () => {
|
|||
});
|
||||
};
|
||||
|
||||
const fileChange = (info: any) => {
|
||||
loading.value = true;
|
||||
if (info.file.status === 'done') {
|
||||
const r = info.file.response || { result: '' };
|
||||
_import(modelRef.configId, { fileUrl: r.result })
|
||||
.then((resp: any) => {
|
||||
totalCount.value = resp.result.total;
|
||||
importStatus.value = true
|
||||
message.success('导入成功')
|
||||
})
|
||||
.catch((err) => {
|
||||
message.error(err.response.data.message || '导入失败')
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
// const fileChange = (info: any) => {
|
||||
// loading.value = true;
|
||||
// if (info.file.status === 'done') {
|
||||
// const r = info.file.response || { result: '' };
|
||||
// _import(modelRef.configId, { fileUrl: r.result })
|
||||
// .then((resp: any) => {
|
||||
// totalCount.value = resp.result.total;
|
||||
// importStatus.value = true;
|
||||
// message.success('导入成功');
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// message.error(err.response.data.message || '导入失败');
|
||||
// })
|
||||
// .finally(() => {
|
||||
// loading.value = false;
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
const downFileFn =async (type: string) => {
|
||||
// const url = `${BASE_API_PATH}/network/card/template.${type}`;
|
||||
// downloadFile(url);
|
||||
const res:any = await exportCard(type)
|
||||
if(res){
|
||||
const blob = new Blob([res], { type: type });
|
||||
const url = URL.createObjectURL(blob);
|
||||
console.log(url);
|
||||
downloadFileByUrl(
|
||||
url,
|
||||
`物联卡导入模版`,
|
||||
type,
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
// const downFileFn = async (type: string) => {
|
||||
// // const url = `${BASE_API_PATH}/network/card/template.${type}`;
|
||||
// // downloadFile(url);
|
||||
// const res: any = await exportCard(type);
|
||||
// if (res) {
|
||||
// const blob = new Blob([res], { type: type });
|
||||
// const url = URL.createObjectURL(blob);
|
||||
// console.log(url);
|
||||
// downloadFileByUrl(url, `物联卡导入模版`, type);
|
||||
// }
|
||||
// };
|
||||
|
||||
const handleCancel = () => {
|
||||
totalCount.value = 0;
|
||||
errCount.value = 0;
|
||||
// totalCount.value = 0;
|
||||
// errCount.value = 0;
|
||||
modelRef.configId = undefined;
|
||||
|
||||
emit('close', true);
|
||||
if (importStatus.value) {
|
||||
emit('save', true)
|
||||
}
|
||||
importStatus.value = false
|
||||
// if (importStatus.value) {
|
||||
// emit('save', true);
|
||||
// }
|
||||
// importStatus.value = false;
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
handleCancel()
|
||||
})
|
||||
}
|
||||
modelRef.configId = undefined;
|
||||
emit('save', true);
|
||||
};
|
||||
|
||||
getConfig();
|
||||
</script>
|
||||
|
@ -188,3 +194,4 @@ getConfig();
|
|||
color: @primary-color;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
<template>
|
||||
<j-space align="end">
|
||||
<j-upload
|
||||
v-model:fileList="modelValue.upload"
|
||||
name="file"
|
||||
:action="FILE_UPLOAD"
|
||||
:headers="{
|
||||
'X-Access-Token': LocalStore.get(TOKEN_KEY),
|
||||
}"
|
||||
:maxCount="1"
|
||||
:showUploadList="false"
|
||||
@change="uploadChange"
|
||||
:accept="
|
||||
props?.file ? `.${props?.file}` : '.xlsx'
|
||||
"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<j-button>
|
||||
<template #icon><AIcon type="UploadOutlined" /></template>
|
||||
文件上传
|
||||
</j-button>
|
||||
</j-upload>
|
||||
<div style="margin-left: 20px">
|
||||
<j-space>
|
||||
下载模板
|
||||
<a @click="downFile('xlsx')">.xlsx</a>
|
||||
<a @click="downFile('csv')">.csv</a>
|
||||
</j-space>
|
||||
</div>
|
||||
</j-space>
|
||||
<div style="margin-top: 20px" v-if="importLoading">
|
||||
<j-badge v-if="flag" status="processing" text="进行中" />
|
||||
<j-badge v-else status="success" text="已完成" />
|
||||
<span>总数量:{{ count }}</span>
|
||||
<p style="color: red">{{ errMessage }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { TOKEN_KEY } from '@/utils/variable';
|
||||
import { LocalStore, onlyMessage } from '@/utils/comm';
|
||||
import { downloadFileByUrl } from '@/utils/utils';
|
||||
import { exportCard, _import } from '@/api/iot-card/cardManagement';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
|
||||
type Emits = {
|
||||
(e: 'update:modelValue', data: string[]): void;
|
||||
};
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const props = defineProps({
|
||||
// 组件双向绑定的值
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
product: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
file: {
|
||||
type: String,
|
||||
default: 'xlsx',
|
||||
},
|
||||
});
|
||||
|
||||
const importLoading = ref<boolean>(false);
|
||||
const flag = ref<boolean>(false);
|
||||
const count = ref<number>(0);
|
||||
const errMessage = ref<string>('');
|
||||
|
||||
const downFile = async (type: string) => {
|
||||
const res: any = await exportCard(type);
|
||||
if (res) {
|
||||
const blob = new Blob([res], { type: type });
|
||||
const url = URL.createObjectURL(blob);
|
||||
downloadFileByUrl(url, `物联卡导入模版`, type);
|
||||
}
|
||||
};
|
||||
|
||||
const beforeUpload = (_file: any) => {
|
||||
const fileType = props?.file === 'csv' ? 'csv' : 'xlsx';
|
||||
const isCsv = _file.type === 'text/csv';
|
||||
const isXlsx =
|
||||
_file.type ===
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||
if (!isCsv && fileType !== 'xlsx') {
|
||||
onlyMessage('请上传.csv格式文件', 'warning');
|
||||
}
|
||||
if (!isXlsx && fileType !== 'csv') {
|
||||
onlyMessage('请上传.xlsx格式文件', 'warning');
|
||||
}
|
||||
return (isCsv && fileType !== 'xlsx') || (isXlsx && fileType !== 'csv');
|
||||
};
|
||||
|
||||
const uploadChange = async (info: Record<string, any>) => {
|
||||
importLoading.value = true;
|
||||
if (info.file.status === 'done') {
|
||||
const resp: any = info.file.response || { result: '' };
|
||||
flag.value = true;
|
||||
_import(props.product, { fileUrl: resp.result })
|
||||
.then((response: any) => {
|
||||
count.value = response.result?.total || 0
|
||||
message.success('导入成功');
|
||||
})
|
||||
.catch((err) => {
|
||||
errMessage.value = err?.response?.data?.message || '导入失败'
|
||||
})
|
||||
.finally(() => {
|
||||
flag.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -26,7 +26,7 @@
|
|||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<h3 class="card-item-content-title">
|
||||
<h3 style='font-size: 16px;width: calc(100% - 90px)'>
|
||||
<Ellipsis>
|
||||
{{ slotProps.name }}
|
||||
</Ellipsis>
|
||||
|
|
|
@ -71,7 +71,7 @@ import { queryPlatformNoPage, recharge } from '@/api/iot-card/cardManagement';
|
|||
import { message } from 'jetlinks-ui-components';
|
||||
import { PaymentMethod } from '@/views/iot-card/data';
|
||||
|
||||
const emit = defineEmits(['change']);
|
||||
const emit = defineEmits(['change', 'save']);
|
||||
|
||||
const btnLoading = ref<boolean>(false);
|
||||
const configList = ref<Record<string, any>[]>([]);
|
||||
|
@ -171,7 +171,7 @@ const handleOk = () => {
|
|||
} else {
|
||||
window.open(resp.result);
|
||||
}
|
||||
emit('change');
|
||||
emit('change', true);
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
})
|
||||
|
|
|
@ -53,7 +53,6 @@ import * as echarts from 'echarts';
|
|||
import { dashboard } from '@/api/link/dashboard';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
getTimeFormat,
|
||||
getTimeByType,
|
||||
arrayReverse,
|
||||
defulteParamsData,
|
||||
|
@ -84,9 +83,7 @@ const getCPUEcharts = async (val: any) => {
|
|||
const value = item.data.value;
|
||||
const nodeID = item.data.clusterNodeId;
|
||||
_cpuXAxis.add(
|
||||
dayjs(value.timestamp).format(
|
||||
getTimeFormat(data.value.type),
|
||||
),
|
||||
dayjs(value.timestamp).format('YYYY-MM-DD HH:mm'),
|
||||
);
|
||||
|
||||
if (!_cpuOptions[nodeID]) {
|
||||
|
|
|
@ -53,7 +53,6 @@ import * as echarts from 'echarts';
|
|||
import { dashboard } from '@/api/link/dashboard';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
getTimeFormat,
|
||||
getTimeByType,
|
||||
arrayReverse,
|
||||
typeDataLine,
|
||||
|
@ -95,9 +94,7 @@ const getJVMEcharts = async (val: any) => {
|
|||
_jvmOptions[nodeID] = [];
|
||||
}
|
||||
_jvmXAxis.add(
|
||||
dayjs(value.timestamp).format(
|
||||
getTimeFormat(data.value.type),
|
||||
),
|
||||
dayjs(value.timestamp).format('YYYY-MM-DD HH:mm'),
|
||||
);
|
||||
_jvmOptions[nodeID].push(_value);
|
||||
});
|
||||
|
|
|
@ -114,6 +114,7 @@ export const defulteParamsData = (group: any, val: any) => [
|
|||
params: {
|
||||
from: dayjs(val.time[0]).valueOf(),
|
||||
to: dayjs(val.time[1]).valueOf(),
|
||||
format: 'YYYY-MM-dd HH:mm',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -150,7 +150,7 @@ const handleSearch = (p: any) => {
|
|||
|
||||
const deviceQuery = (p: any) => {
|
||||
const sorts: any = [];
|
||||
if (props.value) {
|
||||
if (props.value[0]?.value) {
|
||||
sorts.push({
|
||||
name: 'id',
|
||||
value: props.value[0]?.value,
|
||||
|
|
|
@ -47,7 +47,7 @@ const change = (number: number) => {
|
|||
_keys.add(number)
|
||||
}
|
||||
}
|
||||
rowKeys.value = [..._keys.values()]
|
||||
rowKeys.value = [..._keys.values()].sort((a, b) => a - b )
|
||||
emit('update:value', rowKeys.value)
|
||||
emit('change', rowKeys.value)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
]'
|
||||
option-type='button'
|
||||
button-style='solid'
|
||||
@change='updateValue'
|
||||
@change='triggerChange'
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item v-if='showCron' name='cron' :rules="cronRules">
|
||||
|
@ -75,7 +75,7 @@
|
|||
style='max-width: 170px'
|
||||
:precision='0'
|
||||
:min='1'
|
||||
:max='59'
|
||||
:max='unitMax'
|
||||
v-model:value='formModel.period.every'
|
||||
@change='updateValue'
|
||||
>
|
||||
|
@ -87,7 +87,7 @@
|
|||
{ label: "分", value: "minutes" },
|
||||
{ label: "小时", value: "hours" },
|
||||
]'
|
||||
@select='updateValue'
|
||||
@select='periodUnitChange'
|
||||
/>
|
||||
</template>
|
||||
</j-input-number>
|
||||
|
@ -124,6 +124,7 @@ const props = defineProps({
|
|||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
const unitMax = ref<number>(99)
|
||||
|
||||
const cronRules = [
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
|
@ -170,7 +171,9 @@ const showPeriod = computed(() => {
|
|||
return formModel.trigger !== 'cron' && formModel.mod === 'period'
|
||||
})
|
||||
|
||||
|
||||
const updateValue = () => {
|
||||
|
||||
const cloneValue = cloneDeep(formModel)
|
||||
if (cloneValue.trigger === 'cron') {
|
||||
delete cloneValue.when
|
||||
|
@ -186,6 +189,26 @@ const updateValue = () => {
|
|||
emit('update:value', cloneValue)
|
||||
}
|
||||
|
||||
const triggerChange = () => {
|
||||
formModel.when = []
|
||||
formModel.cron = undefined
|
||||
updateValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* 频率单位切换
|
||||
* @param v
|
||||
*/
|
||||
const periodUnitChange = (v: any) => {
|
||||
if(v === 'hours') {
|
||||
unitMax.value = 99999
|
||||
} else {
|
||||
unitMax.value = 99
|
||||
}
|
||||
formModel.period!.every = 1
|
||||
updateValue()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
validateFields: () => new Promise(async (resolve) => {
|
||||
const data = await timerForm.value?.validateFields()
|
||||
|
|
|
@ -147,7 +147,7 @@
|
|||
:danger="true"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => clickDel(record),
|
||||
onConfirm: () => clickDel(record, index),
|
||||
}"
|
||||
:disabled="record.status"
|
||||
>
|
||||
|
@ -358,14 +358,18 @@ const addRow = () => {
|
|||
table.data.push(initData);
|
||||
};
|
||||
|
||||
const clickDel = (row: any) => {
|
||||
const clickDel = (row: any, index: number) => {
|
||||
if (row.scale !== undefined) {
|
||||
delSaveRow_api(id, leftData.selectedKeys[0], [row.name]).then(
|
||||
(resp: any) => {
|
||||
if (resp.status === 200) table.data.splice(row.index, 1);
|
||||
if (resp.status === 200) {
|
||||
table.data.splice(index, 1)
|
||||
}
|
||||
},
|
||||
);
|
||||
} else table.data.splice(row.index, 1);
|
||||
} else {
|
||||
table.data.splice(index, 1)
|
||||
};
|
||||
};
|
||||
|
||||
const clickSave = () => {
|
||||
|
|
|
@ -3700,8 +3700,8 @@ jetlinks-store@^0.0.3:
|
|||
|
||||
jetlinks-ui-components@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#031a300df4df31a353d738cacee8b4ff630ae2d0"
|
||||
integrity sha512-SfucQ7LzlE13VdyZsDhrhzwF9Le/NOke5F6UY3bNN1OJiRD/bZMJecGQxWBQGv567lKcV60SOPCMT8ExiZxUgw==
|
||||
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#a8c912f424b8e6c3e0aa8e2aa9ddcc59fe13cd3a"
|
||||
integrity sha512-zZsVbqG7sLfKsizK+8sT0bCmAz7rEu/qoS5yYSEUzGMvTGQU3Q5W6qdT/5o5v92BYFP+1Kud1l5CNhA3e3NtWQ==
|
||||
dependencies:
|
||||
"@vueuse/core" "^9.12.0"
|
||||
ant-design-vue "^3.2.15"
|
||||
|
|
Loading…
Reference in New Issue