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

This commit is contained in:
JiangQiming 2023-03-29 20:52:50 +08:00
commit ee323a1a7d
28 changed files with 317 additions and 184 deletions

View File

@ -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 queryLogsType = () => server.get(`/dictionary/device-log-type/items`)
export const getDeviceNumber = (data?:any) => server.post<number>('/device-instance/_count', data)

View File

@ -107,8 +107,10 @@ const read = (type: string, data: any) => {
const getList = () => { const getList = () => {
loading.value = true; loading.value = true;
const params = { const params = {
'sorts[0].name': 'notifyTime', sorts: [{
'sorts[0].order': 'desc', name: 'notifyTime',
order: 'desc'
}],
terms: [ terms: [
{ {
terms: [ terms: [

View File

@ -40,14 +40,13 @@
import { FILE_UPLOAD } from '@/api/comm'; import { FILE_UPLOAD } from '@/api/comm';
import { TOKEN_KEY } from '@/utils/variable'; import { TOKEN_KEY } from '@/utils/variable';
import { LocalStore, onlyMessage } from '@/utils/comm'; import { LocalStore, onlyMessage } from '@/utils/comm';
import { downloadFile, downloadFileByUrl } from '@/utils/utils'; import { downloadFileByUrl } from '@/utils/utils';
import { import {
deviceImport, deviceImport,
deviceTemplateDownload,
templateDownload, templateDownload,
} from '@/api/device/instance'; } from '@/api/device/instance';
import { EventSourcePolyfill } from 'event-source-polyfill'; import { EventSourcePolyfill } from 'event-source-polyfill';
import { message } from 'ant-design-vue'; import { message } from 'jetlinks-ui-components';
type Emits = { type Emits = {
(e: 'update:modelValue', data: string[]): void; (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); const importLoading = ref<boolean>(false);
@ -81,7 +89,6 @@ const count = ref<number>(0);
const errMessage = ref<string>(''); const errMessage = ref<string>('');
const downFile = async (type: string) => { const downFile = async (type: string) => {
// downloadFile(deviceTemplateDownload(props.product, type));
const res: any = await templateDownload(props.product, type); const res: any = await templateDownload(props.product, type);
if (res) { if (res) {
const blob = new Blob([res], { type: type }); const blob = new Blob([res], { type: type });

View File

@ -85,6 +85,7 @@
width="700px" width="700px"
@cancel="modalVis = false" @cancel="modalVis = false"
@ok="handleItemModalSubmit" @ok="handleItemModalSubmit"
:zIndex='1100'
> >
<div style="width: 100%; height: 300px"> <div style="width: 100%; height: 300px">
<JMonacoEditor v-model:modelValue="objectValue" /> <JMonacoEditor v-model:modelValue="objectValue" />
@ -157,15 +158,17 @@ const componentsType = ref<ITypes>({
}); });
const typeMap = new Map(Object.entries(componentsType.value)); const typeMap = new Map(Object.entries(componentsType.value));
const myValue = computed({ // const myValue = computed({
get: () => { // get: () => {
return props.modelValue; // return props.modelValue;
}, // },
set: (val: any) => { // set: (val: any) => {
objectValue.value = val; // objectValue.value = val;
emit('update:modelValue', val); // emit('update:modelValue', val);
}, // },
}); // });
const myValue = ref(props.modelValue)
// //
const modalVis = ref<boolean>(false); const modalVis = ref<boolean>(false);
@ -174,6 +177,7 @@ const handleItemModalSubmit = () => {
myValue.value = objectValue.value.replace(/[\r\n]\s*/g, ''); myValue.value = objectValue.value.replace(/[\r\n]\s*/g, '');
modalVis.value = false; modalVis.value = false;
emit('change', objectValue.value) 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) => { const selectChange = (e: string, option: any) => {
emit('change', e, option) emit('change', e, option)
emit('update:modelValue', myValue.value);
} }
const timeChange = (e: any) => { const timeChange = (e: any) => {
emit('change', e) emit('change', e)
emit('update:modelValue', myValue.value);
} }
const inputChange = (e: any) => { const inputChange = (e: any) => {
emit('change', e && e.target ? e.target.value : e) emit('change', e && e.target ? e.target.value : e)
emit('update:modelValue', myValue.value);
} }
const dateChange = (e: any) => { const dateChange = (e: any) => {
emit('change', e) emit('change', e)
emit('update:modelValue', myValue.value);
}
myValue.value = props.modelValue
if (props.itemType === 'object') {
objectValue.value = props.modelValue as string
} }
</script> </script>

View File

@ -187,19 +187,14 @@
<j-form-item <j-form-item
label="采集频率" label="采集频率"
:name="['configuration', 'interval']" :name="['configuration', 'interval']"
:rules="[ :rules="[...ModBusRules.interval]"
...ModBusRules.interval,
{
validator: checkLength,
trigger: 'change',
},
]"
> >
<j-input <j-input-number
style="width: 100%" style="width: 100%"
placeholder="请输入采集频率" placeholder="请输入采集频率"
v-model:value="formData.configuration.interval" v-model:value="formData.configuration.interval"
addon-after="ms" addon-after="ms"
:max="9999999999999998"
/> />
</j-form-item> </j-form-item>
@ -346,15 +341,6 @@ const changeFunction = (value: string) => {
value === 'InputRegisters' ? ['read'] : ['read', 'write']; 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> => const checkProvider = (_rule: Rule, value: string): Promise<any> =>
new Promise(async (resolve, reject) => { new Promise(async (resolve, reject) => {
if (value) { if (value) {

View File

@ -49,19 +49,14 @@
<j-form-item <j-form-item
label="采集频率" label="采集频率"
:name="['configuration', 'interval']" :name="['configuration', 'interval']"
:rules="[ :rules="[...OPCUARules.interval]"
...OPCUARules.interval,
{
validator: checkLength,
trigger: 'change',
},
]"
> >
<j-input <j-input-number
style="width: 100%" style="width: 100%"
placeholder="请输入采集频率" placeholder="请输入采集频率"
v-model:value="formData.configuration.interval" v-model:value="formData.configuration.interval"
addon-after="ms" addon-after="ms"
:max="9999999999999998"
/> />
</j-form-item> </j-form-item>
<j-form-item label="" :name="['features']"> <j-form-item label="" :name="['features']">
@ -156,17 +151,6 @@ const handleCancel = () => {
emit('change', false); 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) => { const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0; return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
}; };

View File

@ -111,17 +111,13 @@
'value', 'value',
]" ]"
:rules="[ :rules="[
{
validator: checkLength,
trigger: 'change',
},
{ {
pattern: regOnlyNumber, pattern: regOnlyNumber,
message: '请输入0或者正整数', message: '请输入0或者正整数',
}, },
]" ]"
> >
<j-input <j-input-number
style="width: 60%" style="width: 60%"
v-model:value=" v-model:value="
record.configuration[dataIndex].value record.configuration[dataIndex].value
@ -129,12 +125,13 @@
placeholder="请输入" placeholder="请输入"
allowClear allowClear
addon-after="ms" addon-after="ms"
:max="9999999999999998"
:disabled=" :disabled="
index !== 0 && index !== 0 &&
record.configuration[dataIndex].check record.configuration[dataIndex].check
" "
@blur="changeValue(index, dataIndex)" @blur="changeValue(index, dataIndex)"
></j-input> ></j-input-number>
<j-checkbox <j-checkbox
style="margin-left: 5px; margin-top: 5px" style="margin-left: 5px; margin-top: 5px"
v-show="index !== 0" v-show="index !== 0"

View File

@ -36,10 +36,6 @@
pattern: regOnlyNumber, pattern: regOnlyNumber,
message: '请输入0或者正整数', message: '请输入0或者正整数',
}, },
{
validator: checkLength,
trigger: 'change',
},
]" ]"
> >
<template #label> <template #label>
@ -53,11 +49,12 @@
</j-tooltip> </j-tooltip>
</span> </span>
</template> </template>
<j-input <j-input-number
style="width: 100%" style="width: 100%"
placeholder="请输入采集频率" placeholder="请输入采集频率"
v-model:value="formData.interval" v-model:value="formData.interval"
addon-after="ms" addon-after="ms"
:max="9999999999999998"
/> />
</j-form-item> </j-form-item>

View File

@ -572,20 +572,20 @@ const handleClick = (dt: any) => {
}; };
const subscribeProperty = (value: any) => { const subscribeProperty = (value: any) => {
const list = value.map((item: any) => item.id); // const list = value.map((item: any) => item.id);
const id = `collector-${props.data?.channelId || 'channel'}-${ // const id = `collector-${props.data?.channelId || 'channel'}-${
props.data?.id || 'point' // props.data?.id || 'point'
}-data-${list.join('-')}`; // }-data-${list.join('-')}`;
const topic = `/collector/${props.data?.channelId || '*'}/${ // const topic = `/collector/${props.data?.channelId || '*'}/${
props.data?.id || '*' // props.data?.id || '*'
}/data`; // }/data`;
subRef.value = getWebSocket(id, topic, { // subRef.value = getWebSocket(id, topic, {
pointId: list.join(','), // pointId: list.join(','),
}) // })
?.pipe(map((res: any) => res.payload)) // ?.pipe(map((res: any) => res.payload))
.subscribe((payload: any) => { // .subscribe((payload: any) => {
propertyValue.value.set(payload.pointId, payload); // propertyValue.value.set(payload.pointId, payload);
}); // });
}; };
const onCheckAllChange = (e: any) => { const onCheckAllChange = (e: any) => {

View File

@ -237,7 +237,8 @@ const handleSearch = async (value: any) => {
if (clickSearch) { if (clickSearch) {
defualtDataSource.value = res.result; defualtDataSource.value = res.result;
if (res.result.length !== 0) { if (res.result.length !== 0) {
selectedKeys.value = [res.result[0].id]; // selectedKeys.value.length === 0 &&
(selectedKeys.value = [res.result[0].id]); //
} }
} else { } else {
defualtDataSource.value = _.cloneDeep(root); defualtDataSource.value = _.cloneDeep(root);
@ -285,7 +286,11 @@ watch(
watch( watch(
() => searchValue.value, () => searchValue.value,
(value) => { (value) => {
!value && handleSearch(value); if (!value) {
setTimeout(() => {
handleSearch(value);
}, 0);
}
}, },
); );
</script> </script>

View File

@ -30,7 +30,7 @@ const changeTree = (row: any) => {
collectorId: row?.id, collectorId: row?.id,
}; };
spinning.value = false; spinning.value = false;
}, 300); }, 1000);
}; };
</script> </script>

View File

@ -86,7 +86,7 @@ export const pointParams = (data: any) => {
from: Number(data.time.time[0]), from: Number(data.time.time[0]),
to: Number(data.time.time[1]), to: Number(data.time.time[1]),
interval: getParams(data.time).interval, interval: getParams(data.time).interval,
format: getParams(data.time).format, format: 'YYYY-MM-dd HH:mm',
}, },
}, },
]; ];

View File

@ -23,7 +23,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { getDeviceNumber } from '@/api/device/product'; import { getDeviceNumber } from '@/api/device/instance';
import { EventSourcePolyfill } from 'event-source-polyfill'; import { EventSourcePolyfill } from 'event-source-polyfill';
const emit = defineEmits(['close', 'save']); const emit = defineEmits(['close', 'save']);
@ -36,6 +36,10 @@ const props = defineProps({
type: String, type: String,
default: '', default: '',
}, },
data: {
type: Object,
default: () => []
}
}); });
const count = ref<number>(0); const count = ref<number>(0);
@ -90,7 +94,7 @@ watch(
() => props.api, () => props.api,
(newValue) => { (newValue) => {
if (newValue) { if (newValue) {
getDeviceNumber({}).then(resp => { getDeviceNumber(props.data).then(resp => {
if(resp.status === 200){ if(resp.status === 200){
total.value = resp.result total.value = resp.result
getData(newValue); getData(newValue);

View File

@ -268,6 +268,7 @@
@close="operationVisible = false" @close="operationVisible = false"
:api="api" :api="api"
:type="type" :type="type"
:data="params"
@save="onRefresh" @save="onRefresh"
/> />
<Save <Save
@ -575,7 +576,7 @@ onMounted(() => {
const handleParams = (config: Record<string, any>) => { const handleParams = (config: Record<string, any>) => {
const _terms: Record<string, any> = {}; const _terms: Record<string, any> = {};
paramsFormat(config, _terms); paramsFormat(config, _terms);
if (Object.keys(_terms._value).length && Object.keys(_terms).length) { if (Object.keys(_terms).length) {
const url = new URLSearchParams(); const url = new URLSearchParams();
Object.keys(_terms).forEach((key) => { Object.keys(_terms).forEach((key) => {
url.append(key, _terms[key]); url.append(key, _terms[key]);
@ -715,7 +716,7 @@ const activeAllDevice = () => {
type.value = 'active'; type.value = 'active';
const activeAPI = `${BASE_API_PATH}/device-instance/deploy?:X_Access_Token=${LocalStore.get( const activeAPI = `${BASE_API_PATH}/device-instance/deploy?:X_Access_Token=${LocalStore.get(
TOKEN_KEY, TOKEN_KEY,
)}&${handleParams(params)}`; )}&${handleParams(params.value)}`;
api.value = activeAPI; api.value = activeAPI;
operationVisible.value = true; operationVisible.value = true;
}; };
@ -724,7 +725,7 @@ const syncDeviceStatus = () => {
type.value = 'sync'; type.value = 'sync';
const syncAPI = `${BASE_API_PATH}/device-instance/state/_sync?:X_Access_Token=${LocalStore.get( const syncAPI = `${BASE_API_PATH}/device-instance/state/_sync?:X_Access_Token=${LocalStore.get(
TOKEN_KEY, TOKEN_KEY,
)}&${handleParams(params)}`; )}&${handleParams(params.value)}`;
api.value = syncAPI; api.value = syncAPI;
operationVisible.value = true; operationVisible.value = true;
}; };

View File

@ -478,12 +478,6 @@ export default {
buttons: [ buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true }, { id: 'view', name: '查看', enabled: true, granted: true },
{ id: 'update', 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: 'delete', name: '删除', enabled: true, granted: true },
{ {
id: 'add', id: 'add',
@ -949,12 +943,6 @@ export default {
buttons: [ buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true }, { id: 'view', name: '查看', enabled: true, granted: true },
{ id: 'update', 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: 'delete', name: '删除', enabled: true, granted: true },
{ {
id: 'add', id: 'add',

View File

@ -2083,8 +2083,9 @@ export default [
], ],
}, },
], ],
accessSupport: { text: "不支持", value: "unsupported" }, accessSupport: { text: "支持", value: "support" },
supportDataAccess: false supportDataAccess: true,
assetType: 'aliyunNorthOutput'
}, },
], ],
}, },

View File

@ -6,11 +6,15 @@
title="导入" title="导入"
okText="确定" okText="确定"
cancelText="取消" cancelText="取消"
@ok="handleOk"
@cancel="handleCancel" @cancel="handleCancel"
> >
<div style="margin-top: 10px"> <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-form-item label="平台对接" required name="configId">
<j-select <j-select
showSearch showSearch
@ -33,6 +37,14 @@
</j-form-item> </j-form-item>
<j-form-item label="文件上传" v-if="modelRef.configId"> <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 <j-upload
v-model:fileList="modelRef.upload" v-model:fileList="modelRef.upload"
name="file" name="file"
@ -70,30 +82,30 @@
<a-icon class="check-num" style="color: red" type="close" /> <a-icon class="check-num" style="color: red" type="close" />
失败 总数量 失败 总数量
<span class="check-num">{{ errCount }}</span> <span class="check-num">{{ errCount }}</span>
</div> </div> -->
</j-form>
</div> </div>
<template #footer>
<j-button type="primary" @click="handleOk">关闭</j-button>
</template>
</j-modal> </j-modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { FILE_UPLOAD } from '@/api/comm'; // import { downloadFile, downloadFileByUrl } from '@/utils/utils';
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable'; import {
import { LocalStore } from '@/utils/comm'; queryPlatformNoPage,
import { downloadFile, downloadFileByUrl } from '@/utils/utils'; _import,
import { queryPlatformNoPage, _import ,exportCard} from '@/api/iot-card/cardManagement'; } from '@/api/iot-card/cardManagement';
// import { message } from 'ant-design-vue'; import UploadFile from './UploadFile.vue'
import { message } from 'jetlinks-ui-components';
const emit = defineEmits(['close', 'save']); const emit = defineEmits(['close', 'save']);
const configList = ref<Record<string, any>[]>([]); const configList = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false); // const loading = ref<boolean>(false);
const totalCount = ref<number>(0); // const totalCount = ref<number>(0);
const errCount = ref<number>(0); // const errCount = ref<number>(0);
const formRef = ref(null) const formRef = ref(null);
const importStatus = ref(false) // const importStatus = ref(false);
const modelRef = reactive({ const modelRef = reactive({
configId: undefined, configId: undefined,
upload: [], upload: [],
@ -101,8 +113,8 @@ const modelRef = reactive({
}); });
const rules = { const rules = {
configId: [{ required: true, message: '请选择平台对接'}] configId: [{ required: true, message: '请选择平台对接' }],
} };
const getConfig = async () => { const getConfig = async () => {
const resp: any = await queryPlatformNoPage({ const resp: any = await queryPlatformNoPage({
@ -125,59 +137,53 @@ const getConfig = async () => {
}); });
}; };
const fileChange = (info: any) => { // const fileChange = (info: any) => {
loading.value = true; // loading.value = true;
if (info.file.status === 'done') { // if (info.file.status === 'done') {
const r = info.file.response || { result: '' }; // const r = info.file.response || { result: '' };
_import(modelRef.configId, { fileUrl: r.result }) // _import(modelRef.configId, { fileUrl: r.result })
.then((resp: any) => { // .then((resp: any) => {
totalCount.value = resp.result.total; // totalCount.value = resp.result.total;
importStatus.value = true // importStatus.value = true;
message.success('导入成功') // message.success('');
}) // })
.catch((err) => { // .catch((err) => {
message.error(err.response.data.message || '导入失败') // message.error(err.response.data.message || '');
}) // })
.finally(() => { // .finally(() => {
loading.value = false; // loading.value = false;
}); // });
} // }
}; // };
const downFileFn =async (type: string) => { // const downFileFn = async (type: string) => {
// const url = `${BASE_API_PATH}/network/card/template.${type}`; // // const url = `${BASE_API_PATH}/network/card/template.${type}`;
// downloadFile(url); // // downloadFile(url);
const res:any = await exportCard(type) // const res: any = await exportCard(type);
if(res){ // if (res) {
const blob = new Blob([res], { type: type }); // const blob = new Blob([res], { type: type });
const url = URL.createObjectURL(blob); // const url = URL.createObjectURL(blob);
console.log(url); // console.log(url);
downloadFileByUrl( // downloadFileByUrl(url, ``, type);
url, // }
`物联卡导入模版`, // };
type,
);
}
};
const handleCancel = () => { const handleCancel = () => {
totalCount.value = 0; // totalCount.value = 0;
errCount.value = 0; // errCount.value = 0;
modelRef.configId = undefined; modelRef.configId = undefined;
emit('close', true); emit('close', true);
if (importStatus.value) { // if (importStatus.value) {
emit('save', true) // emit('save', true);
} // }
importStatus.value = false // importStatus.value = false;
}; };
const handleOk = () => { const handleOk = () => {
formRef.value.validate().then(res => { modelRef.configId = undefined;
handleCancel() emit('save', true);
}) };
}
getConfig(); getConfig();
</script> </script>
@ -188,3 +194,4 @@ getConfig();
color: @primary-color; color: @primary-color;
} }
</style> </style>

View File

@ -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>

View File

@ -26,7 +26,7 @@
</slot> </slot>
</template> </template>
<template #content> <template #content>
<h3 class="card-item-content-title"> <h3 style='font-size: 16px;width: calc(100% - 90px)'>
<Ellipsis> <Ellipsis>
{{ slotProps.name }} {{ slotProps.name }}
</Ellipsis> </Ellipsis>

View File

@ -71,7 +71,7 @@ import { queryPlatformNoPage, recharge } from '@/api/iot-card/cardManagement';
import { message } from 'jetlinks-ui-components'; import { message } from 'jetlinks-ui-components';
import { PaymentMethod } from '@/views/iot-card/data'; import { PaymentMethod } from '@/views/iot-card/data';
const emit = defineEmits(['change']); const emit = defineEmits(['change', 'save']);
const btnLoading = ref<boolean>(false); const btnLoading = ref<boolean>(false);
const configList = ref<Record<string, any>[]>([]); const configList = ref<Record<string, any>[]>([]);
@ -171,7 +171,7 @@ const handleOk = () => {
} else { } else {
window.open(resp.result); window.open(resp.result);
} }
emit('change'); emit('change', true);
formRef.value.resetFields(); formRef.value.resetFields();
} }
}) })

View File

@ -53,7 +53,6 @@ import * as echarts from 'echarts';
import { dashboard } from '@/api/link/dashboard'; import { dashboard } from '@/api/link/dashboard';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { import {
getTimeFormat,
getTimeByType, getTimeByType,
arrayReverse, arrayReverse,
defulteParamsData, defulteParamsData,
@ -84,9 +83,7 @@ const getCPUEcharts = async (val: any) => {
const value = item.data.value; const value = item.data.value;
const nodeID = item.data.clusterNodeId; const nodeID = item.data.clusterNodeId;
_cpuXAxis.add( _cpuXAxis.add(
dayjs(value.timestamp).format( dayjs(value.timestamp).format('YYYY-MM-DD HH:mm'),
getTimeFormat(data.value.type),
),
); );
if (!_cpuOptions[nodeID]) { if (!_cpuOptions[nodeID]) {

View File

@ -53,7 +53,6 @@ import * as echarts from 'echarts';
import { dashboard } from '@/api/link/dashboard'; import { dashboard } from '@/api/link/dashboard';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { import {
getTimeFormat,
getTimeByType, getTimeByType,
arrayReverse, arrayReverse,
typeDataLine, typeDataLine,
@ -95,9 +94,7 @@ const getJVMEcharts = async (val: any) => {
_jvmOptions[nodeID] = []; _jvmOptions[nodeID] = [];
} }
_jvmXAxis.add( _jvmXAxis.add(
dayjs(value.timestamp).format( dayjs(value.timestamp).format('YYYY-MM-DD HH:mm'),
getTimeFormat(data.value.type),
),
); );
_jvmOptions[nodeID].push(_value); _jvmOptions[nodeID].push(_value);
}); });

View File

@ -114,6 +114,7 @@ export const defulteParamsData = (group: any, val: any) => [
params: { params: {
from: dayjs(val.time[0]).valueOf(), from: dayjs(val.time[0]).valueOf(),
to: dayjs(val.time[1]).valueOf(), to: dayjs(val.time[1]).valueOf(),
format: 'YYYY-MM-dd HH:mm',
}, },
}, },
]; ];

View File

@ -150,7 +150,7 @@ const handleSearch = (p: any) => {
const deviceQuery = (p: any) => { const deviceQuery = (p: any) => {
const sorts: any = []; const sorts: any = [];
if (props.value) { if (props.value[0]?.value) {
sorts.push({ sorts.push({
name: 'id', name: 'id',
value: props.value[0]?.value, value: props.value[0]?.value,

View File

@ -47,7 +47,7 @@ const change = (number: number) => {
_keys.add(number) _keys.add(number)
} }
} }
rowKeys.value = [..._keys.values()] rowKeys.value = [..._keys.values()].sort((a, b) => a - b )
emit('update:value', rowKeys.value) emit('update:value', rowKeys.value)
emit('change', rowKeys.value) emit('change', rowKeys.value)
} }

View File

@ -15,7 +15,7 @@
]' ]'
option-type='button' option-type='button'
button-style='solid' button-style='solid'
@change='updateValue' @change='triggerChange'
/> />
</j-form-item> </j-form-item>
<j-form-item v-if='showCron' name='cron' :rules="cronRules"> <j-form-item v-if='showCron' name='cron' :rules="cronRules">
@ -75,7 +75,7 @@
style='max-width: 170px' style='max-width: 170px'
:precision='0' :precision='0'
:min='1' :min='1'
:max='59' :max='unitMax'
v-model:value='formModel.period.every' v-model:value='formModel.period.every'
@change='updateValue' @change='updateValue'
> >
@ -87,7 +87,7 @@
{ label: "分", value: "minutes" }, { label: "分", value: "minutes" },
{ label: "小时", value: "hours" }, { label: "小时", value: "hours" },
]' ]'
@select='updateValue' @select='periodUnitChange'
/> />
</template> </template>
</j-input-number> </j-input-number>
@ -124,6 +124,7 @@ const props = defineProps({
}) })
const emit = defineEmits<Emit>() const emit = defineEmits<Emit>()
const unitMax = ref<number>(99)
const cronRules = [ const cronRules = [
{ max: 64, message: '最多可输入64个字符' }, { max: 64, message: '最多可输入64个字符' },
@ -170,7 +171,9 @@ const showPeriod = computed(() => {
return formModel.trigger !== 'cron' && formModel.mod === 'period' return formModel.trigger !== 'cron' && formModel.mod === 'period'
}) })
const updateValue = () => { const updateValue = () => {
const cloneValue = cloneDeep(formModel) const cloneValue = cloneDeep(formModel)
if (cloneValue.trigger === 'cron') { if (cloneValue.trigger === 'cron') {
delete cloneValue.when delete cloneValue.when
@ -186,6 +189,26 @@ const updateValue = () => {
emit('update:value', cloneValue) 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({ defineExpose({
validateFields: () => new Promise(async (resolve) => { validateFields: () => new Promise(async (resolve) => {
const data = await timerForm.value?.validateFields() const data = await timerForm.value?.validateFields()

View File

@ -147,7 +147,7 @@
:danger="true" :danger="true"
:popConfirm="{ :popConfirm="{
title: `确认删除`, title: `确认删除`,
onConfirm: () => clickDel(record), onConfirm: () => clickDel(record, index),
}" }"
:disabled="record.status" :disabled="record.status"
> >
@ -358,14 +358,18 @@ const addRow = () => {
table.data.push(initData); table.data.push(initData);
}; };
const clickDel = (row: any) => { const clickDel = (row: any, index: number) => {
if (row.scale !== undefined) { if (row.scale !== undefined) {
delSaveRow_api(id, leftData.selectedKeys[0], [row.name]).then( delSaveRow_api(id, leftData.selectedKeys[0], [row.name]).then(
(resp: any) => { (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 = () => { const clickSave = () => {

View File

@ -3700,8 +3700,8 @@ jetlinks-store@^0.0.3:
jetlinks-ui-components@^1.0.5: jetlinks-ui-components@^1.0.5:
version "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" resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#a8c912f424b8e6c3e0aa8e2aa9ddcc59fe13cd3a"
integrity sha512-SfucQ7LzlE13VdyZsDhrhzwF9Le/NOke5F6UY3bNN1OJiRD/bZMJecGQxWBQGv567lKcV60SOPCMT8ExiZxUgw== integrity sha512-zZsVbqG7sLfKsizK+8sT0bCmAz7rEu/qoS5yYSEUzGMvTGQU3Q5W6qdT/5o5v92BYFP+1Kud1l5CNhA3e3NtWQ==
dependencies: dependencies:
"@vueuse/core" "^9.12.0" "@vueuse/core" "^9.12.0"
ant-design-vue "^3.2.15" ant-design-vue "^3.2.15"