fix: 替换vue3-markdown-it为markdown-it
* fix: 替换vue3-markdown-it为markdown-it
This commit is contained in:
parent
f75d40f223
commit
926cc90cd3
4
build.sh
4
build.sh
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
docker build -t registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.2.0-SNAPSHOT .
|
||||
docker push registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.2.0-SNAPSHOT
|
||||
docker build -t registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.1.0-TEST .
|
||||
docker push registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.1.0-TEST
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
API_BASE_PATH=$API_BASE_PATH;
|
||||
SERVER_NAME=$SERVER_NAME
|
||||
SERVER_NAME=$SERVER_NAME;
|
||||
|
||||
NAMESERVERS=$(cat /etc/resolv.conf | grep "nameserver" | awk '{print $2}' | tr '\n' ' ')
|
||||
if [ -z "$API_BASE_PATH" ]; then
|
||||
API_BASE_PATH="http://jetlinks:8844/";
|
||||
|
@ -17,6 +18,8 @@ serverName="server_name $SERVER_NAME;"
|
|||
|
||||
sed -i '4c '"$serverName"'' /etc/nginx/conf.d/default.conf
|
||||
sed -i '11c '"$resolver"'' /etc/nginx/conf.d/default.conf
|
||||
sed -i '20c '"$apiUrl"'' /etc/nginx/conf.d/default.conf
|
||||
sed -i '25c '"$apiUrl"'' /etc/nginx/conf.d/default.conf
|
||||
sed -i 's/\${SERVER_NAME}/'$SERVER_NAME'/g' /etc/nginx/conf.d/default.conf
|
||||
|
||||
nginx -g "daemon off;"
|
||||
|
||||
|
|
|
@ -11,6 +11,11 @@ server {
|
|||
resolver $NAMESERVERS ipv6=off;
|
||||
root /usr/share/nginx/html;
|
||||
include /etc/nginx/mime.types;
|
||||
|
||||
if ($http_Host !~* ^${SERVER_NAME}) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
location / {
|
||||
index index.html;
|
||||
}
|
||||
|
|
17
package.json
17
package.json
|
@ -27,11 +27,23 @@
|
|||
"global": "^4.4.0",
|
||||
"jetlinks-store": "^0.0.3",
|
||||
"jetlinks-ui-components": "^1.0.38",
|
||||
"js-cookie": "^3.0.1",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^11.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markdown-it-abbr": "^2.0.0",
|
||||
"markdown-it-anchor": "^8.6.7",
|
||||
"markdown-it-deflist": "^3.0.0",
|
||||
"markdown-it-emoji": "^3.0.0",
|
||||
"markdown-it-footnote": "^4.0.0",
|
||||
"markdown-it-highlightjs": "^4.0.1",
|
||||
"markdown-it-ins": "^4.0.0",
|
||||
"markdown-it-mark": "^4.0.0",
|
||||
"markdown-it-sub": "^2.0.0",
|
||||
"markdown-it-sup": "^2.0.0",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"markdown-it-toc-done-right": "^4.2.0",
|
||||
"marked": "^4.2.12",
|
||||
"moment": "^2.29.4",
|
||||
"monaco-editor": "^0.36.0",
|
||||
|
@ -43,12 +55,11 @@
|
|||
"unplugin-vue-components": "^0.22.12",
|
||||
"v-clipboard3": "^0.1.4",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"vue": "^3.2.45",
|
||||
"vue": "3.3.4",
|
||||
"vue-cropper": "^1.0.9",
|
||||
"vue-json-viewer": "^3.0.4",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue3-json-viewer": "^2.2.2",
|
||||
"vue3-markdown-it": "^1.0.10",
|
||||
"vue3-ts-jsoneditor": "^2.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -47,7 +47,7 @@ import type { OperatorItem } from './typings';
|
|||
import { treeFilter } from '@/utils/tree'
|
||||
import { PropertyMetadata } from '@/views/device/Product/typings';
|
||||
import { getOperator } from '@/api/device/product'
|
||||
import Markdown from 'vue3-markdown-it'
|
||||
import Markdown from '@/components/Markdown'
|
||||
|
||||
const props = defineProps({
|
||||
id: String
|
||||
|
|
|
@ -2,16 +2,69 @@
|
|||
<div class="debug-container">
|
||||
<div class="top">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">
|
||||
属性赋值
|
||||
<div class="description">
|
||||
请对上方规则使用的属性进行赋值
|
||||
<j-tabs v-model:activeKey="headerType">
|
||||
<j-tab-pane key="property">
|
||||
<template #tab>
|
||||
<span class="title">
|
||||
属性赋值
|
||||
</span>
|
||||
</template>
|
||||
</j-tab-pane>
|
||||
<j-tab-pane key="tag">
|
||||
<template #tab>
|
||||
<span class="title">
|
||||
标签赋值
|
||||
</span>
|
||||
</template>
|
||||
</j-tab-pane>
|
||||
</j-tabs>
|
||||
<!-- <div>
|
||||
<j-dropdown>
|
||||
<div class="title" @click.prevent>
|
||||
{{
|
||||
headerType === 'property'
|
||||
? '属性赋值'
|
||||
: '标签赋值'
|
||||
}}
|
||||
<div class="description">
|
||||
{{
|
||||
`请对上方规则使用的${
|
||||
headerType === 'property'
|
||||
? '属性'
|
||||
: '标签'
|
||||
}进行赋值`
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #overlay>
|
||||
<j-menu>
|
||||
<j-menu-item>
|
||||
<a
|
||||
href="javascript:;"
|
||||
@click="headerType = 'property'"
|
||||
>属性赋值</a
|
||||
>
|
||||
</j-menu-item>
|
||||
<j-menu-item>
|
||||
<a
|
||||
href="javascript:;"
|
||||
@click="headerType = 'tag'"
|
||||
>标签赋值</a
|
||||
>
|
||||
</j-menu-item>
|
||||
</j-menu>
|
||||
</template>
|
||||
</j-dropdown>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="top-bottom">
|
||||
<div class="description">
|
||||
{{
|
||||
`请对上方规则使用的${
|
||||
headerType === 'property' ? '属性' : '标签'
|
||||
}进行赋值`
|
||||
}}
|
||||
</div>
|
||||
<div class="top-bottom" v-if="headerType === 'property'">
|
||||
<j-table
|
||||
:columns="columns"
|
||||
:data-source="property"
|
||||
|
@ -62,6 +115,51 @@
|
|||
添加条目
|
||||
</j-button>
|
||||
</div>
|
||||
<div class="top-bottom" v-if="headerType === 'tag'">
|
||||
<j-table
|
||||
:columns="tagColumns"
|
||||
:data-source="tag"
|
||||
:pagination="false"
|
||||
bordered
|
||||
size="small"
|
||||
:scroll="{ y: 200 }"
|
||||
>
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.key === 'id'">
|
||||
<j-select
|
||||
showSearch
|
||||
:options="tagOptions"
|
||||
v-model:value="record.id"
|
||||
size="small"
|
||||
style="width: 100%; z-index: 1400 !important"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="column.key === 'current'">
|
||||
<j-input
|
||||
v-model:value="record.current"
|
||||
size="small"
|
||||
></j-input>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
@click="deleteTagItem(index)"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
</j-table>
|
||||
<j-button
|
||||
type="dashed"
|
||||
block
|
||||
style="margin-top: 5px"
|
||||
@click="addTagItem"
|
||||
>
|
||||
<template #icon>
|
||||
<AIcon type="PlusOutlined" />
|
||||
</template>
|
||||
添加条目
|
||||
</j-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="header">
|
||||
|
@ -98,7 +196,9 @@
|
|||
:span="3"
|
||||
>
|
||||
<template #label>
|
||||
<template v-if="!!runningState(index + 1, item._time)">
|
||||
<template
|
||||
v-if="!!runningState(index + 1, item._time)"
|
||||
>
|
||||
{{ runningState(index + 1, item._time) }}
|
||||
</template>
|
||||
<template v-else>{{
|
||||
|
@ -140,7 +240,19 @@ type propertyType = {
|
|||
last?: string;
|
||||
};
|
||||
const property = ref<propertyType[]>([]);
|
||||
|
||||
const tag = ref<Array<any>>([]);
|
||||
const headerOptions = [
|
||||
{
|
||||
key: 'property',
|
||||
label: '属性赋值',
|
||||
title: '属性赋值',
|
||||
},
|
||||
{
|
||||
key: 'tag',
|
||||
label: '标签赋值',
|
||||
title: '标签赋值',
|
||||
},
|
||||
];
|
||||
const columns = [
|
||||
{
|
||||
title: '属性名称',
|
||||
|
@ -164,17 +276,42 @@ const columns = [
|
|||
},
|
||||
];
|
||||
|
||||
const tagColumns = [
|
||||
{
|
||||
title: '属性名称',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: '当前值',
|
||||
dataIndex: 'current',
|
||||
key: 'current',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 50,
|
||||
},
|
||||
];
|
||||
const headerType = ref('property');
|
||||
const addItem = () => {
|
||||
property.value.push({});
|
||||
};
|
||||
const addTagItem = () => {
|
||||
tag.value.push({});
|
||||
};
|
||||
const deleteItem = (index: number) => {
|
||||
property.value.splice(index, 1);
|
||||
};
|
||||
const deleteTagItem = (index: number) => {
|
||||
tag.value.splice(index, 1);
|
||||
};
|
||||
|
||||
const ws = ref();
|
||||
|
||||
const virtualIdRef = ref(new Date().getTime());
|
||||
const medataSource = inject<Ref<any[]>>('_dataSource');
|
||||
const tagsSource = inject<Ref<any[]>>('_tagsDataSource');
|
||||
const productStore = useProductStore();
|
||||
const ruleEditorStore = useRuleEditorStore();
|
||||
|
||||
|
@ -188,7 +325,10 @@ const runScript = () => {
|
|||
const _item = propertiesList.find((i: any) => i.id === item.id);
|
||||
return { ...item, type: _item?.valueType?.type };
|
||||
});
|
||||
|
||||
let _tags = {};
|
||||
tag.value.forEach((item) => {
|
||||
_tags[item.id] = item.current;
|
||||
});
|
||||
if (ws.value) {
|
||||
ws.value.unsubscribe?.();
|
||||
}
|
||||
|
@ -208,12 +348,13 @@ const runScript = () => {
|
|||
...props.virtualRule,
|
||||
},
|
||||
properties: _properties || [],
|
||||
tags: _tags,
|
||||
},
|
||||
).subscribe((data: any) => {
|
||||
ruleEditorStore.state.log.push({
|
||||
time: new Date().getTime(),
|
||||
content: JSON.stringify(data.payload),
|
||||
_time: unref(time.value)
|
||||
_time: unref(time.value),
|
||||
});
|
||||
emits('success', false);
|
||||
if (props.virtualRule?.type !== 'window') {
|
||||
|
@ -275,8 +416,8 @@ const stopAction = () => {
|
|||
if (ws.value) {
|
||||
ws.value.unsubscribe?.();
|
||||
}
|
||||
window.clearInterval(timer.value)
|
||||
timer.value = null
|
||||
window.clearInterval(timer.value);
|
||||
timer.value = null;
|
||||
};
|
||||
const clearAction = () => {
|
||||
ruleEditorStore.set('log', []);
|
||||
|
@ -287,8 +428,8 @@ onUnmounted(() => {
|
|||
ws.value.unsubscribe?.();
|
||||
}
|
||||
clearAction();
|
||||
window.clearInterval(timer.value)
|
||||
timer.value = null
|
||||
window.clearInterval(timer.value);
|
||||
timer.value = null;
|
||||
});
|
||||
|
||||
const options = computed(() => {
|
||||
|
@ -300,6 +441,13 @@ const options = computed(() => {
|
|||
}));
|
||||
});
|
||||
|
||||
const tagOptions = computed(() => {
|
||||
return (tagsSource.value || []).map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
});
|
||||
|
||||
// const getProperty = () => {
|
||||
// // const metadata = productStore.current.metadata || '{}';
|
||||
// // const _p: PropertyMetadata[] = JSON.parse(metadata).properties || [];
|
||||
|
|
|
@ -7,70 +7,104 @@
|
|||
placeholder="搜索关键字"
|
||||
/>
|
||||
<div class="tree">
|
||||
<j-scrollbar>
|
||||
|
||||
|
||||
<j-tree
|
||||
@select="selectTree"
|
||||
:field-names="{ title: 'name', key: 'id' }"
|
||||
auto-expand-parent
|
||||
:tree-data="data"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="node">
|
||||
<div class="node">
|
||||
<div style="max-width: 160px">
|
||||
<Ellipsis>{{ node.name }}</Ellipsis>
|
||||
</div>
|
||||
<div
|
||||
:class="
|
||||
node.children?.length > 0 ? 'parent' : 'add'
|
||||
"
|
||||
>
|
||||
<j-popover
|
||||
v-if="node.type === 'property'"
|
||||
:overlayStyle="{
|
||||
zIndex: 1200
|
||||
}"
|
||||
placement="right"
|
||||
title="请选择使用值"
|
||||
<j-scrollbar>
|
||||
<j-tree
|
||||
@select="selectTree"
|
||||
:field-names="{ title: 'name', key: 'id' }"
|
||||
auto-expand-parent
|
||||
:tree-data="data"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="node">
|
||||
<div class="node">
|
||||
<div style="max-width: 160px">
|
||||
<Ellipsis>{{ node.name }}</Ellipsis>
|
||||
</div>
|
||||
<div
|
||||
:class="
|
||||
node.children?.length > 0
|
||||
? 'parent'
|
||||
: 'add'
|
||||
"
|
||||
>
|
||||
<template #content>
|
||||
<j-space direction="vertical">
|
||||
<j-tooltip
|
||||
placement="right"
|
||||
title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值"
|
||||
>
|
||||
<j-button
|
||||
type="text"
|
||||
@click="recentClick(node)"
|
||||
<j-popover
|
||||
v-if="node.type === 'property'"
|
||||
:overlayStyle="{
|
||||
zIndex: 1200,
|
||||
}"
|
||||
placement="right"
|
||||
title="请选择使用值"
|
||||
>
|
||||
<template #content>
|
||||
<j-space direction="vertical">
|
||||
<j-tooltip
|
||||
placement="right"
|
||||
title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值"
|
||||
>
|
||||
$recent实时值
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
<j-tooltip
|
||||
placement="right"
|
||||
title="实时值的上一有效值"
|
||||
>
|
||||
<j-button
|
||||
@click="lastClick(node)"
|
||||
type="text"
|
||||
<j-button
|
||||
type="text"
|
||||
@click="
|
||||
recentClick(node)
|
||||
"
|
||||
>
|
||||
$recent实时值
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
<j-tooltip
|
||||
placement="right"
|
||||
title="实时值的上一有效值"
|
||||
>
|
||||
上一值
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<a class="has-property">添加</a>
|
||||
</j-popover>
|
||||
|
||||
<a class="no-property" v-else @click.stop="addClick(node)"> 添加 </a>
|
||||
<j-button
|
||||
@click="lastClick(node)"
|
||||
type="text"
|
||||
>
|
||||
上一值
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<a class="has-property">添加</a>
|
||||
</j-popover>
|
||||
<j-popover
|
||||
v-else-if="node.type === 'tags'"
|
||||
:overlayStyle="{
|
||||
zIndex: 1200,
|
||||
}"
|
||||
placement="right"
|
||||
title="请选择使用值"
|
||||
>
|
||||
<template #content>
|
||||
<j-space direction="vertical">
|
||||
<j-tooltip
|
||||
placement="right"
|
||||
title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值"
|
||||
>
|
||||
<j-button
|
||||
type="text"
|
||||
@click="
|
||||
recentTagsClick(node)
|
||||
"
|
||||
>
|
||||
tag实时值
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<a class="has-property">添加</a>
|
||||
</j-popover>
|
||||
<a
|
||||
class="no-property"
|
||||
v-else
|
||||
@click.stop="addClick(node)"
|
||||
>
|
||||
添加
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</j-tree>
|
||||
</j-scrollbar>
|
||||
</template>
|
||||
</j-tree>
|
||||
</j-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
|
@ -84,11 +118,13 @@ import type { OperatorItem } from './typings';
|
|||
import { treeFilter } from '@/utils/tree';
|
||||
import { PropertyMetadata } from '@/views/device/Product/typings';
|
||||
import { getOperator } from '@/api/device/product';
|
||||
import Markdown from 'vue3-markdown-it';
|
||||
import { inject } from 'vue';
|
||||
import { Descriptions } from 'ant-design-vue';
|
||||
import Markdown from '@/components/Markdown'
|
||||
|
||||
const props = defineProps({
|
||||
id: String,
|
||||
propertiesOptions: Array
|
||||
propertiesOptions: Array,
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
|
@ -99,7 +135,7 @@ const emit = defineEmits<Emits>();
|
|||
const item = ref<Partial<OperatorItem>>();
|
||||
const data = ref<OperatorItem[]>([]);
|
||||
const dataRef = ref<OperatorItem[]>([]);
|
||||
|
||||
const tagsMetadata: any = inject('_tagsDataSource');
|
||||
const search = (value: string) => {
|
||||
if (value) {
|
||||
const nodes = treeFilter(
|
||||
|
@ -117,6 +153,9 @@ const selectTree = (k: any, info: any) => {
|
|||
item.value = info.node as unknown as OperatorItem;
|
||||
};
|
||||
|
||||
const recentTagsClick = (node:OperatorItem) =>{
|
||||
emit('addOperatorValue',`tag("${node.id}")`)
|
||||
}
|
||||
const recentClick = (node: OperatorItem) => {
|
||||
emit('addOperatorValue', `$recent("${node.id}")`);
|
||||
};
|
||||
|
@ -131,7 +170,7 @@ const productStore = useProductStore();
|
|||
|
||||
const getData = async (id?: string) => {
|
||||
// const metadata = productStore.current.metadata || '{}';
|
||||
const _properties = props.propertiesOptions as PropertyMetadata[]
|
||||
const _properties = props.propertiesOptions as PropertyMetadata[];
|
||||
const properties = {
|
||||
id: 'property',
|
||||
name: '属性',
|
||||
|
@ -149,10 +188,33 @@ const getData = async (id?: string) => {
|
|||
type: 'property',
|
||||
})),
|
||||
};
|
||||
const tags = {
|
||||
id: 'tags',
|
||||
name: '标签',
|
||||
Description: '',
|
||||
code: '',
|
||||
children: tagsMetadata.value.map((i: any) => ({
|
||||
id: i.id,
|
||||
name: i.name,
|
||||
description: `### ${i.name}
|
||||
\n 数据类型: ${i.valueType?.type}
|
||||
\n 是否只读: ${i.expands?.readOnly || 'false'}
|
||||
\n 可写数值范围: `,
|
||||
type: 'tags',
|
||||
})),
|
||||
};
|
||||
const response = await getOperator();
|
||||
if (response.status === 200) {
|
||||
data.value = [properties as OperatorItem, ...response.result];
|
||||
dataRef.value = [properties as OperatorItem, ...response.result];
|
||||
data.value = [
|
||||
properties as OperatorItem,
|
||||
tags as any,
|
||||
...response.result,
|
||||
];
|
||||
dataRef.value = [
|
||||
properties as OperatorItem,
|
||||
tags as any,
|
||||
...response.result,
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -186,7 +248,6 @@ watch(
|
|||
padding: 10px;
|
||||
margin-right: 10px;
|
||||
.tree {
|
||||
|
||||
height: 300px;
|
||||
//overflow-y: auto;
|
||||
|
||||
|
@ -203,12 +264,12 @@ watch(
|
|||
}
|
||||
|
||||
.right {
|
||||
padding: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.rule-popover {
|
||||
z-index: 1200;
|
||||
z-index: 1200;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,117 @@
|
|||
import { h, onMounted, onUpdated, ref } from 'vue';
|
||||
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import MarkdownItAbbr from 'markdown-it-abbr';
|
||||
import MarkdownItAnchor from 'markdown-it-anchor';
|
||||
import MarkdownItDeflist from 'markdown-it-deflist';
|
||||
import { full as emoji } from 'markdown-it-emoji'
|
||||
import MarkdownItFootnote from 'markdown-it-footnote';
|
||||
import MarkdownItHighlightjs from 'markdown-it-highlightjs';
|
||||
import MarkdownItIns from 'markdown-it-ins';
|
||||
import MarkdownItMark from 'markdown-it-mark';
|
||||
import MarkdownItSub from 'markdown-it-sub';
|
||||
import MarkdownItSup from 'markdown-it-sup';
|
||||
import MarkdownItTasklists from 'markdown-it-task-lists';
|
||||
import MarkdownItTOC from 'markdown-it-toc-done-right';
|
||||
|
||||
const props = {
|
||||
anchor: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
breaks: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
emoji: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
highlight: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
html: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
langPrefix: {
|
||||
type: String,
|
||||
default: 'language-'
|
||||
},
|
||||
linkify: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
plugins: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
quotes: {
|
||||
type: String,
|
||||
default: '“”‘’'
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
tasklists: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
toc: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
typographer: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xhtmlOut: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'Markdown',
|
||||
props,
|
||||
setup(props) {
|
||||
const md = ref();
|
||||
const renderMarkdown = () => {
|
||||
let markdown = new MarkdownIt()
|
||||
.use(MarkdownItAbbr)
|
||||
.use(MarkdownItAnchor, props.anchor)
|
||||
.use(MarkdownItDeflist)
|
||||
.use(emoji, props.emoji)
|
||||
.use(MarkdownItFootnote)
|
||||
.use(MarkdownItHighlightjs, props.highlight)
|
||||
.use(MarkdownItIns)
|
||||
.use(MarkdownItMark)
|
||||
.use(MarkdownItSub)
|
||||
.use(MarkdownItSup)
|
||||
.use(MarkdownItTasklists, props.tasklists)
|
||||
.use(MarkdownItTOC, props.toc)
|
||||
.set({
|
||||
breaks: props.breaks,
|
||||
html: props.html,
|
||||
langPrefix: props.langPrefix,
|
||||
linkify: props.linkify,
|
||||
quotes: props.quotes,
|
||||
typographer: props.typographer,
|
||||
xhtmlOut: props.xhtmlOut
|
||||
});
|
||||
|
||||
props.plugins.forEach(({ plugin, options = {} }) => {
|
||||
markdown.use(plugin, options);
|
||||
});
|
||||
|
||||
md.value = markdown.render(props.source);
|
||||
};
|
||||
|
||||
onMounted(() => renderMarkdown());
|
||||
onUpdated(() => renderMarkdown());
|
||||
|
||||
return () => h('div', { innerHTML: md.value, style: { height: '100%'} });
|
||||
}
|
||||
};
|
|
@ -11,6 +11,7 @@ import JProUpload from './Upload/index.vue'
|
|||
import { BasicLayoutPage, BlankLayoutPage, FullPage } from './Layout'
|
||||
import RadioCard from './RadioCard/index.vue'
|
||||
import { PageContainer, AIcon, Ellipsis } from 'jetlinks-ui-components'
|
||||
import MarkDown from './Markdown'
|
||||
// import Ellipsis from './Ellipsis/index.vue'
|
||||
import JEmpty from './Empty/index.vue'
|
||||
import AMapComponent from './AMapComponent/index.vue'
|
||||
|
@ -41,5 +42,6 @@ export default {
|
|||
.component('RowPagination', RowPagination)
|
||||
.component('FullPage', FullPage)
|
||||
.component('RadioCard', RadioCard)
|
||||
.component('MarkDown', MarkDown)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ declare module '*.gif';
|
|||
declare module '*.bmp';
|
||||
declare module '*.js';
|
||||
declare module '*.ts';
|
||||
declare module 'js-cookie';
|
||||
declare module 'jetlinks-ui-components';
|
||||
declare module 'vue3-json-viewer';
|
||||
declare module 'event-source-polyfill';
|
|
@ -1,4 +1,4 @@
|
|||
import JSEncrypt from "jsencrypt";
|
||||
import JSEncrypt from "jsencrypt/bin/jsencrypt.min.js";
|
||||
|
||||
export const encrypt =(txt:string,publicKey:string)=>{
|
||||
const encryptor = new JSEncrypt()
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
v-if="
|
||||
showLoad ||
|
||||
(!getType(record?.value) &&
|
||||
data?.valueType?.fileType === 'base64')
|
||||
data?.valueType?.bodyType === 'base64')
|
||||
"
|
||||
type="link"
|
||||
@click="_download(record)"
|
||||
|
@ -128,7 +128,7 @@ const columns = computed(() => {
|
|||
const showLoad = computed(() => {
|
||||
return (
|
||||
_props.data.valueType?.type === 'file' &&
|
||||
_props.data?.valueType?.fileType === 'Binary(二进制)'
|
||||
_props.data?.valueType?.bodyType === 'Binary(二进制)'
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
--
|
||||
</div>
|
||||
<div v-else-if="_data.data?.valueType?.type === 'file'">
|
||||
<template v-if="data?.valueType?.fileType === 'base64'">
|
||||
<template v-if="data?.valueType?.bodyType === 'base64'">
|
||||
<div :class="valueClass" v-if="!!getType(value?.formatValue)">
|
||||
<img :src="imgMap.get(_type)" @error="onError" />
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<div
|
||||
v-else-if="data?.valueType?.fileType === 'Binary(二进制)'"
|
||||
v-else-if="data?.valueType?.bodyType === 'Binary(二进制)'"
|
||||
:class="valueClass"
|
||||
>
|
||||
<img :src="imgMap.get('other')" />
|
||||
|
|
|
@ -89,26 +89,22 @@ const productName = computed(() => {
|
|||
})
|
||||
|
||||
const handleOk = async () => {
|
||||
|
||||
const params = paramsEncodeQuery(props.data);
|
||||
// downloadFile(
|
||||
// deviceExport(modelRef.product || '', modelRef.fileType),
|
||||
// params,
|
||||
// );
|
||||
// const res: any = await deviceExport(
|
||||
// modelRef.product || '',
|
||||
// modelRef.fileType,
|
||||
// params
|
||||
// );
|
||||
console.log(props.data,params)
|
||||
window.open(`${deviceExportPath( modelRef.product || '',modelRef.fileType)}?X-Access-Token=${getToken()
|
||||
}`)
|
||||
// if (res) {
|
||||
// const blob = new Blob([res], { type: modelRef.fileType });
|
||||
// const url = URL.createObjectURL(blob);
|
||||
// downloadFileByUrl(url, `${productName.value ? (productName.value + '下设备') : '设备实例'}`, modelRef.fileType);
|
||||
// emit('close');
|
||||
// }
|
||||
const res: any = await deviceExport(
|
||||
modelRef.product || '',
|
||||
modelRef.fileType,
|
||||
params
|
||||
);
|
||||
if (res) {
|
||||
const blob = new Blob([res], { type: modelRef.fileType });
|
||||
const url = URL.createObjectURL(blob);
|
||||
downloadFileByUrl(url, `${productName.value ? (productName.value + '下设备') : '设备实例'}`, modelRef.fileType);
|
||||
emit('close');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
|
|
|
@ -334,7 +334,7 @@ import BatchDropdown from '@/components/BatchDropdown/index.vue';
|
|||
import { BatchActionsType } from '@/components/BatchDropdown/types';
|
||||
import { useRouterParams } from '@/utils/hooks/useParams';
|
||||
import { accessConfigTypeFilter } from '@/utils/setting';
|
||||
import TagSearch from './components/TagSearch.vue'
|
||||
import TagSearch from './components/TagSearch.vue';
|
||||
|
||||
const instanceRef = ref<Record<string, any>>({});
|
||||
const params = ref<Record<string, any>>({});
|
||||
|
@ -478,7 +478,15 @@ const columns = [
|
|||
type: 'select',
|
||||
options: () =>
|
||||
new Promise((resolve) => {
|
||||
queryGatewayList({}).then((resp: any) => {
|
||||
queryGatewayList({
|
||||
paging: false,
|
||||
sorts: [
|
||||
{
|
||||
name: 'createTime',
|
||||
order: 'desc',
|
||||
},
|
||||
],
|
||||
}).then((resp: any) => {
|
||||
resolve(
|
||||
resp.result.map((item: any) => ({
|
||||
label: item.name,
|
||||
|
@ -509,6 +517,7 @@ const columns = [
|
|||
hideInTable: true,
|
||||
search: {
|
||||
type: 'treeSelect',
|
||||
termOptions: ['eq'],
|
||||
// handleValue(v) {
|
||||
// return {
|
||||
// assetType: 'device',
|
||||
|
@ -554,7 +563,11 @@ const columns = [
|
|||
dataIndex: 'id$dev-tag',
|
||||
title: '设备标签',
|
||||
hideInTable: true,
|
||||
search : { type: 'component' , components: TagSearch , termOptions:['eq'] }
|
||||
search: {
|
||||
type: 'component',
|
||||
components: TagSearch,
|
||||
termOptions: ['eq'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
|
@ -720,7 +733,9 @@ const getActions = (
|
|||
const resp = await _delete(data.id);
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!');
|
||||
const index = _selectedRowKeys.value.findIndex((id: any) => id === data.id);
|
||||
const index = _selectedRowKeys.value.findIndex(
|
||||
(id: any) => id === data.id,
|
||||
);
|
||||
if (index !== -1) {
|
||||
_selectedRowKeys.value.splice(index, 1);
|
||||
}
|
||||
|
|
|
@ -303,6 +303,7 @@ const {basicLayout} = storeToRefs(system);
|
|||
const router = useRouter()
|
||||
|
||||
const { data: metadata, noEdit, productNoEdit } = useMetadata(_target, props.type);
|
||||
const { data: tagsMetadata } = useMetadata(_target,'tags')
|
||||
const { hasOperate } = useOperateLimits(_target);
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
|
@ -339,7 +340,8 @@ const showLastDelete = computed(() => {
|
|||
return dataSourceCache.value.length === 1
|
||||
})
|
||||
|
||||
provide('_dataSource', dataSourceCache)
|
||||
provide('_dataSource', dataSourceCache);
|
||||
provide('_tagsDataSource',tagsMetadata)
|
||||
const showDetail = (data: any) => {
|
||||
detailData.data = data
|
||||
detailData.visible = true
|
||||
|
@ -558,6 +560,7 @@ onUnmounted(() => {
|
|||
|
||||
watch(() => metadata.value, () => {
|
||||
dataSource.value = metadata.value
|
||||
|
||||
}, { immediate: true })
|
||||
|
||||
onBeforeRouteUpdate((to, from, next) => { // 设备管理内路由跳转
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<a-descriptions-item v-if="['int', 'long', 'float', 'double'].includes(data.valueType.type)" label="单位">{{ unitLabel }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="['float', 'double'].includes(data.valueType.type)" label="精度">{{ data.valueType?.scale }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="['string', 'password'].includes(data.valueType.type)" label="最大长度">{{ data.valueType?.maxLength }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="data.valueType.type === 'file'" label="文件类型">{{ data.valueType?.fileType }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="data.valueType.type === 'file'" label="文件类型">{{ data.valueType?.bodyType }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="data.valueType.type === 'date'" label="格式">{{ data.valueType?.format }}</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
v-if="
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<a-descriptions-item v-if="['int', 'long', 'float', 'double'].includes(data.valueType.type)" label="单位">{{ unitLabel }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="['float', 'double'].includes(data.valueType.type)" label="精度">{{ data.valueType?.scale }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="['string', 'password'].includes(data.valueType.type)" label="最大长度">{{ data.valueType?.maxLength }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="data.valueType.type === 'file'" label="文件类型">{{ data.valueType?.fileType }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="data.valueType.type === 'file'" label="文件类型">{{ data.valueType?.bodyType }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="data.valueType.type === 'date'" label="格式">{{ data.valueType?.format }}</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
v-if="
|
||||
|
|
|
@ -47,11 +47,11 @@
|
|||
]">
|
||||
<JsonParam v-model:value="_value.properties" :name="name.concat(['properties'])"></JsonParam>
|
||||
</j-form-item>
|
||||
<j-form-item label="文件类型" :name="name.concat(['fileType'])" v-if="['file'].includes(_value.type)" initialValue="url"
|
||||
<j-form-item label="文件类型" :name="name.concat(['bodyType'])" v-if="['file'].includes(_value.type)" initialValue="url"
|
||||
:rules="[
|
||||
{ required: true, message: '请选择文件类型' },
|
||||
]">
|
||||
<j-select v-model:value="_value.fileType" :options="FileTypeList" size="small" placeholder="请选择文件类型"></j-select>
|
||||
<j-select v-model:value="_value.bodyType" :options="FileTypeList" size="small" placeholder="请选择文件类型"></j-select>
|
||||
</j-form-item>
|
||||
</template>
|
||||
<script lang="ts" setup mame="BaseForm">
|
||||
|
@ -158,7 +158,7 @@ const changeType = (val: SelectValue) => {
|
|||
_value.value.scale = 2
|
||||
}
|
||||
if (['file'].includes(val as string)) {
|
||||
_value.value.fileType = _value.value.fileType || 'url'
|
||||
_value.value.bodyType = _value.value.bodyType || 'url'
|
||||
}
|
||||
if (['date'].includes(val as string)) {
|
||||
_value.value.format = _value.value.format || 'yyyy-MM-dd HH:mm:ss'
|
||||
|
|
|
@ -52,7 +52,7 @@ export const validateValueType = async (_rule: Rule, val: Record<any, any>, titl
|
|||
if (['object'].includes(val.type)) {
|
||||
await validateJson(_rule, val.properties)
|
||||
}
|
||||
if (['file'].includes(val.type) && !val.fileType) {
|
||||
if (['file'].includes(val.type) && !val.bodyType) {
|
||||
return Promise.reject(new Error('请选择文件类型'))
|
||||
}
|
||||
return Promise.resolve();
|
||||
|
|
|
@ -53,7 +53,7 @@ export const validatorConfig = (value: any, _isObject: boolean = false) => {
|
|||
return Promise.reject('请添加参数')
|
||||
}
|
||||
|
||||
if (value.type === 'file' && (!value.fileType || (isObject(value.fileType) && !Object.keys(value.fileType).length))) {
|
||||
if (value.type === 'file' && (!value.bodyType || (isObject(value.bodyType) && !Object.keys(value.bodyType).length))) {
|
||||
return Promise.reject('请选择文件类型')
|
||||
}
|
||||
|
||||
|
@ -65,9 +65,16 @@ export const handleTypeValue = (type:string, value: any = {}) => {
|
|||
switch (type) {
|
||||
//bug#22609
|
||||
case 'array':
|
||||
if(value.type === 'array'){
|
||||
obj.elementType = {
|
||||
...value,
|
||||
elementType:{
|
||||
type: 'object',
|
||||
properties: []
|
||||
}
|
||||
}
|
||||
}else{
|
||||
obj.elementType = value
|
||||
}
|
||||
break;
|
||||
case 'object':
|
||||
|
@ -80,7 +87,7 @@ export const handleTypeValue = (type:string, value: any = {}) => {
|
|||
obj.unit = value
|
||||
break;
|
||||
case 'file':
|
||||
obj.fileType = value
|
||||
obj.bodyType = value
|
||||
break;
|
||||
case 'date':
|
||||
obj.format = value
|
||||
|
@ -119,7 +126,7 @@ export const typeSelectChange = (type: string) => {
|
|||
obj.unit = undefined
|
||||
break;
|
||||
case 'file':
|
||||
obj.fileType = undefined
|
||||
obj.bodyType = undefined
|
||||
break;
|
||||
case 'date':
|
||||
obj.format = undefined
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
</DataTableInteger>
|
||||
<DataTableFile
|
||||
v-else-if="type === 'file'"
|
||||
v-model:value="myValue.fileType"
|
||||
v-model:value="myValue.bodyType"
|
||||
placement="topRight"
|
||||
@confirm="valueChange"
|
||||
>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
placement="bottomRight"
|
||||
@confirm="(data) => {valueChange(data, 'int')}"
|
||||
/>
|
||||
<DataTableFile v-else-if="type === 'file'" v-model:value="_valueType.fileType" placement="bottomRight" @confirm="(data) => {valueChange(data, 'file')}"/>
|
||||
<DataTableFile v-else-if="type === 'file'" v-model:value="_valueType.bodyType" placement="bottomRight" @confirm="(data) => {valueChange(data, 'file')}"/>
|
||||
<DataTableDate v-else-if="type === 'date'" v-model:value="_valueType.format" placement="bottomRight" @confirm="(data) => {valueChange(data, 'date')}"/>
|
||||
<DataTableString
|
||||
v-else-if="['string', 'password'].includes(type)"
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
placement="topRight"
|
||||
v-model:value="formData.unit"
|
||||
/>
|
||||
<DataTableFile v-else-if="formData.type === 'file'" v-model:value="formData.fileType" placement="topRight"/>
|
||||
<DataTableFile v-else-if="formData.type === 'file'" v-model:value="formData.bodyType" placement="topRight"/>
|
||||
<DataTableDate v-else-if="formData.type === 'date'" v-model:value="formData.date" placement="topRight"/>
|
||||
<DataTableString
|
||||
v-else-if="['string', 'password'].includes(formData.type)"
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
v-model:value="data.unit"
|
||||
@confirm="valueChange"
|
||||
/>
|
||||
<DataTableFile v-else-if="type === 'file'" placement="bottomRight" v-model:value="data.fileType" @confirm="valueChange"/>
|
||||
<DataTableFile v-else-if="type === 'file'" placement="bottomRight" v-model:value="data.bodyType" @confirm="valueChange"/>
|
||||
<DataTableDate v-else-if="type === 'date'" placement="bottomRight" v-model:value="data.date" @confirm="valueChange"/>
|
||||
<DataTableString
|
||||
v-else-if="['string', 'password'].includes(type)"
|
||||
|
|
|
@ -20,7 +20,9 @@ const useMetadata = (type: 'device' | 'product', key?: MetadataType, ): {
|
|||
const { current: productCurrent } = storeToRefs(productStore)
|
||||
|
||||
const handleMetadata = (_metadataStr: string) => {
|
||||
const _metadata = JSON.parse(_metadataStr || '{}')
|
||||
const fileTypeReg = new RegExp('"fileType":',"g")
|
||||
const _dealMetadata = _metadataStr.replaceAll(fileTypeReg,'"bodyType":')
|
||||
const _metadata = JSON.parse(_dealMetadata || '{}')
|
||||
const newMetadata = (key ? _metadata?.[key] || [] : []) as any[]
|
||||
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ export const testType = (data:any,index:number,isArray?:boolean,isObject?:boolea
|
|||
}
|
||||
}
|
||||
if(data.type === 'file' && !isArray && !isObject){
|
||||
if(!data?.fileType){
|
||||
if(!data?.bodyType){
|
||||
onlyMessage(`方法定义inputs第${index+1}个数组ValueType中缺失fileType属性`,'error')
|
||||
return true
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ export const testAliType = (data:any,index:number,isArray?:boolean,isObject?:boo
|
|||
}
|
||||
}
|
||||
if(data.dataType.type === 'file' && !isArray && !isObject){
|
||||
if(!data.dataType?.fileType){
|
||||
if(!data.dataType?.bodyType){
|
||||
onlyMessage(`方法定义inputs第${index+1}个数组dataType中缺失fileType属性`,'error')
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -7,38 +7,40 @@
|
|||
@search="handleSearch"
|
||||
/>
|
||||
<FullPage>
|
||||
<j-pro-table
|
||||
:scroll="{ x: 1366 }"
|
||||
ref="cardManageRef"
|
||||
:columns="columns"
|
||||
:request="query"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
:rowSelection="
|
||||
isCheck
|
||||
? {
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
}
|
||||
: false
|
||||
"
|
||||
:params="params"
|
||||
:gridColumn="3"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<j-space>
|
||||
<PermissionButton
|
||||
@click="handleAdd"
|
||||
:hasPermission="'iot-card/CardManagement:add'"
|
||||
type="primary"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<BatchDropdown
|
||||
v-model:isCheck="isCheck"
|
||||
:actions="batchActions"
|
||||
@change="onCheckChange"
|
||||
/>
|
||||
<!-- <j-dropdown>
|
||||
<j-pro-table
|
||||
:scroll="{ x: 1366 }"
|
||||
ref="cardManageRef"
|
||||
:columns="columns"
|
||||
:request="query"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
}"
|
||||
:rowSelection="
|
||||
isCheck
|
||||
? {
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
}
|
||||
: false
|
||||
"
|
||||
:params="params"
|
||||
:gridColumn="3"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<j-space>
|
||||
<PermissionButton
|
||||
@click="handleAdd"
|
||||
:hasPermission="'iot-card/CardManagement:add'"
|
||||
type="primary"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<BatchDropdown
|
||||
v-model:isCheck="isCheck"
|
||||
:actions="batchActions"
|
||||
@change="onCheckChange"
|
||||
/>
|
||||
<!-- <j-dropdown>
|
||||
<j-button>
|
||||
批量操作
|
||||
<AIcon type="DownOutlined" />
|
||||
|
@ -133,206 +135,222 @@
|
|||
</j-menu>
|
||||
</template>
|
||||
</j-dropdown> -->
|
||||
</j-space>
|
||||
</template>
|
||||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value="slotProps"
|
||||
@click="handleClick"
|
||||
:actions="getActions(slotProps, 'card')"
|
||||
v-bind="slotProps"
|
||||
:active="_selectedRowKeys.includes(slotProps.id)"
|
||||
:status="slotProps.cardStateType?.value"
|
||||
:statusText="slotProps.cardStateType?.text"
|
||||
:statusNames="{
|
||||
using: 'processing',
|
||||
toBeActivated: 'default',
|
||||
deactivate: 'error',
|
||||
}"
|
||||
>
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img :src="getImage('/iot-card/iot-card-bg.png')" />
|
||||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
<Ellipsis style="width: calc(100% - 100px)">
|
||||
{{ slotProps.id }}
|
||||
</Ellipsis>
|
||||
</span>
|
||||
<j-row style="margin-top: 20px">
|
||||
<j-col :span="8">
|
||||
<div class="card-item-content-text">
|
||||
平台对接
|
||||
</div>
|
||||
<Ellipsis style="width: calc(100% - 20px)">
|
||||
<div>{{ slotProps.platformConfigName }}</div>
|
||||
</Ellipsis>
|
||||
</j-col>
|
||||
<j-col :span="6">
|
||||
<div class="card-item-content-text">类型</div>
|
||||
<div>{{ slotProps.cardType.text }}</div>
|
||||
</j-col>
|
||||
<j-col :span="6">
|
||||
<div class="card-item-content-text">
|
||||
绑定设备
|
||||
</div>
|
||||
<Ellipsis>{{ slotProps.deviceName }}</Ellipsis>
|
||||
</j-col>
|
||||
</j-row>
|
||||
<j-divider style="margin: 12px 0" />
|
||||
<div class="content-bottom">
|
||||
<div>
|
||||
<div class="progress-text">
|
||||
<div>
|
||||
{{
|
||||
slotProps.totalFlow ? (
|
||||
(slotProps.usedFlow /
|
||||
slotProps.totalFlow) *
|
||||
100
|
||||
).toFixed(2) : '0.00'
|
||||
}}
|
||||
%
|
||||
</div>
|
||||
<div class="card-item-content-text">
|
||||
总共 {{ slotProps.totalFlow }} M
|
||||
</div>
|
||||
</div>
|
||||
<j-progress
|
||||
:strokeColor="'#ADC6FF'"
|
||||
:showInfo="false"
|
||||
:percent="
|
||||
slotProps.totalFlow ? (slotProps.usedFlow /
|
||||
slotProps.totalFlow) *
|
||||
100 : 0
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
<PermissionButton
|
||||
:disabled="item.disabled"
|
||||
:popConfirm="item.popConfirm"
|
||||
:tooltip="{
|
||||
...item.tooltip,
|
||||
}"
|
||||
@click="item.onClick"
|
||||
:hasPermission="
|
||||
'iot-card/CardManagement:' + item.key
|
||||
"
|
||||
>
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
v-if="item.key === 'delete'"
|
||||
/>
|
||||
<template v-else>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</template>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
<template #deviceId="slotProps">
|
||||
{{ slotProps.deviceName }}
|
||||
</template>
|
||||
<template #totalFlow="slotProps">
|
||||
<div>
|
||||
{{
|
||||
slotProps.totalFlow
|
||||
? slotProps.totalFlow.toFixed(2) + ' M'
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template #usedFlow="slotProps">
|
||||
<div>
|
||||
{{
|
||||
slotProps.usedFlow
|
||||
? slotProps.usedFlow.toFixed(2) + ' M'
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template #residualFlow="slotProps">
|
||||
<div>
|
||||
{{
|
||||
slotProps.residualFlow
|
||||
? slotProps.residualFlow.toFixed(2) + ' M'
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template #operatorName='slotProps'>
|
||||
{{ OperatorMap[slotProps.operatorName]}}
|
||||
</template>
|
||||
<template #cardType="slotProps">
|
||||
{{ slotProps.cardType.text }}
|
||||
</template>
|
||||
<template #cardStateType="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.cardStateType?.value"
|
||||
:text="slotProps.cardStateType?.text"
|
||||
:statusNames="{
|
||||
using: 'processing',
|
||||
toBeActivated: 'default',
|
||||
deactivate: 'error',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
<template #activationDate="slotProps">
|
||||
{{
|
||||
slotProps.activationDate
|
||||
? dayjs(slotProps.activationDate).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
}}
|
||||
</template>
|
||||
<template #updateTime="slotProps">
|
||||
{{
|
||||
slotProps.updateTime
|
||||
? dayjs(slotProps.updateTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
}}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<j-space :size="16">
|
||||
<template
|
||||
v-for="i in getActions(slotProps, 'table')"
|
||||
:key="i.key"
|
||||
</j-space>
|
||||
</template>
|
||||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value="slotProps"
|
||||
@click="handleClick"
|
||||
:actions="getActions(slotProps, 'card')"
|
||||
v-bind="slotProps"
|
||||
:active="_selectedRowKeys.includes(slotProps.id)"
|
||||
:status="slotProps.cardStateType?.value"
|
||||
:statusText="slotProps.cardStateType?.text"
|
||||
:statusNames="{
|
||||
using: 'processing',
|
||||
toBeActivated: 'default',
|
||||
deactivate: 'error',
|
||||
}"
|
||||
>
|
||||
<PermissionButton
|
||||
:disabled="i.disabled"
|
||||
:popConfirm="i.popConfirm"
|
||||
:tooltip="{
|
||||
...i.tooltip,
|
||||
}"
|
||||
@click="i.onClick"
|
||||
type="link"
|
||||
style="padding: 0px"
|
||||
:hasPermission="
|
||||
i.key === 'view'
|
||||
? true
|
||||
: 'iot-card/CardManagement:' + i.key
|
||||
"
|
||||
:danger="i.key === 'delete'"
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img
|
||||
:src="getImage('/iot-card/iot-card-bg.png')"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
<Ellipsis style="width: calc(100% - 100px)">
|
||||
{{ slotProps.id }}
|
||||
</Ellipsis>
|
||||
</span>
|
||||
<j-row style="margin-top: 20px">
|
||||
<j-col :span="8">
|
||||
<div class="card-item-content-text">
|
||||
平台对接
|
||||
</div>
|
||||
<Ellipsis style="width: calc(100% - 20px)">
|
||||
<div>
|
||||
{{ slotProps.platformConfigName }}
|
||||
</div>
|
||||
</Ellipsis>
|
||||
</j-col>
|
||||
<j-col :span="6">
|
||||
<div class="card-item-content-text">
|
||||
类型
|
||||
</div>
|
||||
<div>{{ slotProps.cardType.text }}</div>
|
||||
</j-col>
|
||||
<j-col :span="6">
|
||||
<div class="card-item-content-text">
|
||||
绑定设备
|
||||
</div>
|
||||
<Ellipsis>{{
|
||||
slotProps.deviceName
|
||||
}}</Ellipsis>
|
||||
</j-col>
|
||||
</j-row>
|
||||
<j-divider style="margin: 12px 0" />
|
||||
<div class="content-bottom">
|
||||
<div>
|
||||
<div class="progress-text">
|
||||
<div>
|
||||
{{
|
||||
slotProps.totalFlow
|
||||
? (
|
||||
(slotProps.usedFlow /
|
||||
slotProps.totalFlow) *
|
||||
100
|
||||
).toFixed(2)
|
||||
: '0.00'
|
||||
}}
|
||||
%
|
||||
</div>
|
||||
<div class="card-item-content-text">
|
||||
总共 {{ slotProps.totalFlow }} M
|
||||
</div>
|
||||
</div>
|
||||
<j-progress
|
||||
:strokeColor="'#ADC6FF'"
|
||||
:showInfo="false"
|
||||
:percent="
|
||||
slotProps.totalFlow
|
||||
? (slotProps.usedFlow /
|
||||
slotProps.totalFlow) *
|
||||
100
|
||||
: 0
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
<PermissionButton
|
||||
:disabled="item.disabled"
|
||||
:popConfirm="item.popConfirm"
|
||||
:tooltip="{
|
||||
...item.tooltip,
|
||||
}"
|
||||
@click="item.onClick"
|
||||
:hasPermission="
|
||||
'iot-card/CardManagement:' + item.key
|
||||
"
|
||||
>
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
v-if="item.key === 'delete'"
|
||||
/>
|
||||
<template v-else>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</template>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
<template #deviceId="slotProps">
|
||||
{{ slotProps.deviceName }}
|
||||
</template>
|
||||
<template #totalFlow="slotProps">
|
||||
<div>
|
||||
{{
|
||||
slotProps.totalFlow
|
||||
? slotProps.totalFlow.toFixed(2) + ' M'
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template #usedFlow="slotProps">
|
||||
<div>
|
||||
{{
|
||||
slotProps.usedFlow
|
||||
? slotProps.usedFlow.toFixed(2) + ' M'
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template #residualFlow="slotProps">
|
||||
<div>
|
||||
{{
|
||||
slotProps.residualFlow
|
||||
? slotProps.residualFlow.toFixed(2) + ' M'
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template #operatorName="slotProps">
|
||||
{{ OperatorMap[slotProps.operatorName] }}
|
||||
</template>
|
||||
<template #cardType="slotProps">
|
||||
{{ slotProps.cardType.text }}
|
||||
</template>
|
||||
<template #cardStateType="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.cardStateType?.value"
|
||||
:text="slotProps.cardStateType?.text"
|
||||
:statusNames="{
|
||||
using: 'processing',
|
||||
toBeActivated: 'default',
|
||||
deactivate: 'error',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
<template #activationDate="slotProps">
|
||||
{{
|
||||
slotProps.activationDate
|
||||
? dayjs(slotProps.activationDate).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
}}
|
||||
</template>
|
||||
<template #updateTime="slotProps">
|
||||
{{
|
||||
slotProps.updateTime
|
||||
? dayjs(slotProps.updateTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
}}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<j-space :size="16">
|
||||
<template
|
||||
v-for="i in getActions(slotProps, 'table')"
|
||||
:key="i.key"
|
||||
>
|
||||
<template #icon>
|
||||
<AIcon :type="i.icon" />
|
||||
</template>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</j-space>
|
||||
</template>
|
||||
</j-pro-table>
|
||||
<PermissionButton
|
||||
:disabled="i.disabled"
|
||||
:popConfirm="i.popConfirm"
|
||||
:tooltip="{
|
||||
...i.tooltip,
|
||||
}"
|
||||
@click="i.onClick"
|
||||
type="link"
|
||||
style="padding: 0px"
|
||||
:hasPermission="
|
||||
i.key === 'view'
|
||||
? true
|
||||
: 'iot-card/CardManagement:' + i.key
|
||||
"
|
||||
:danger="i.key === 'delete'"
|
||||
>
|
||||
<template #icon>
|
||||
<AIcon :type="i.icon" />
|
||||
</template>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</j-space>
|
||||
</template>
|
||||
</j-pro-table>
|
||||
</FullPage>
|
||||
<!-- 批量导入 -->
|
||||
<Import v-if="importVisible" @close="importVisible = false" @save="importSave"/>
|
||||
<Import
|
||||
v-if="importVisible"
|
||||
@close="importVisible = false"
|
||||
@save="importSave"
|
||||
/>
|
||||
<!-- 批量导出 -->
|
||||
<Export
|
||||
v-if="exportVisible"
|
||||
|
@ -382,9 +400,9 @@ import { useMenuStore } from 'store/menu';
|
|||
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
||||
import BatchDropdown from '@/components/BatchDropdown/index.vue';
|
||||
import { BatchActionsType } from '@/components/BatchDropdown/types';
|
||||
import {usePermissionStore} from "store/permission";
|
||||
import {useRouterParams} from "@/utils/hooks/useParams";
|
||||
import { OperatorList, OperatorMap } from '@/views/iot-card/data'
|
||||
import { usePermissionStore } from 'store/permission';
|
||||
import { useRouterParams } from '@/utils/hooks/useParams';
|
||||
import { OperatorMap } from '@/views/iot-card/data';
|
||||
|
||||
const router = useRouter();
|
||||
const menuStory = useMenuStore();
|
||||
|
@ -432,9 +450,9 @@ const columns = [
|
|||
scopedSlots: true,
|
||||
width: 200,
|
||||
search: {
|
||||
type: 'string',
|
||||
rename: 'deviceName'
|
||||
}
|
||||
type: 'string',
|
||||
rename: 'deviceName',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '平台对接',
|
||||
|
@ -467,7 +485,22 @@ const columns = [
|
|||
width: 120,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: OperatorList,
|
||||
options: async () => {
|
||||
return [
|
||||
{
|
||||
label: '移动',
|
||||
value: '移动',
|
||||
},
|
||||
{
|
||||
label: '电信',
|
||||
value: '电信',
|
||||
},
|
||||
{
|
||||
label: '联通',
|
||||
value: '联通',
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -538,7 +571,7 @@ const columns = [
|
|||
{ label: '未激活', value: 'toBeActivated' },
|
||||
{ label: '停机', value: 'deactivate' },
|
||||
{ label: '其它', value: 'using,toBeActivated,deactivate' },
|
||||
]
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -552,11 +585,11 @@ const columns = [
|
|||
const btnHasPermission = usePermissionStore().hasPermission;
|
||||
const paltformPermission = btnHasPermission(`iot-card/Platform:add`);
|
||||
const importSave = () => {
|
||||
cardManageRef.value?.reload()
|
||||
importVisible.value = false
|
||||
}
|
||||
cardManageRef.value?.reload();
|
||||
importVisible.value = false;
|
||||
};
|
||||
|
||||
const routerParams = useRouterParams()
|
||||
const routerParams = useRouterParams();
|
||||
|
||||
const getActions = (
|
||||
data: Partial<Record<string, any>>,
|
||||
|
@ -680,7 +713,9 @@ const getActions = (
|
|||
const resp: any = await del(data.id);
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功');
|
||||
const index = _selectedRowKeys.value.findIndex((id: any) => id === data.id);
|
||||
const index = _selectedRowKeys.value.findIndex(
|
||||
(id: any) => id === data.id,
|
||||
);
|
||||
if (index !== -1) {
|
||||
_selectedRowKeys.value.splice(index, 1);
|
||||
}
|
||||
|
@ -716,15 +751,19 @@ const getActions = (
|
|||
};
|
||||
|
||||
const handleSearch = (e: any) => {
|
||||
const newParams = (e?.terms as any[])?.map(item1 => {
|
||||
item1.terms = item1.terms.map((item2: any) => {
|
||||
if (['cardStateType'].includes(item2.column) && !(['using', 'toBeActivated', 'deactivate'].includes(item2.value))) { // 处理其它状态
|
||||
item2.termType = item2.termType === 'not' ? 'in' : 'nin'
|
||||
}
|
||||
return item2
|
||||
})
|
||||
return item1
|
||||
})
|
||||
const newParams = (e?.terms as any[])?.map((item1) => {
|
||||
item1.terms = item1.terms.map((item2: any) => {
|
||||
if (
|
||||
['cardStateType'].includes(item2.column) &&
|
||||
!['using', 'toBeActivated', 'deactivate'].includes(item2.value)
|
||||
) {
|
||||
// 处理其它状态
|
||||
item2.termType = item2.termType === 'not' ? 'in' : 'nin';
|
||||
}
|
||||
return item2;
|
||||
});
|
||||
return item1;
|
||||
});
|
||||
params.value = { terms: newParams || [] };
|
||||
};
|
||||
|
||||
|
@ -738,8 +777,8 @@ const cancelSelect = () => {
|
|||
};
|
||||
|
||||
const handleClick = (dt: any) => {
|
||||
if(!dt?.cardStateType){
|
||||
return
|
||||
if (!dt?.cardStateType) {
|
||||
return;
|
||||
}
|
||||
if (isCheck.value) {
|
||||
if (_selectedRowKeys.value.includes(dt.id)) {
|
||||
|
@ -797,7 +836,7 @@ const bindDevice = (val: boolean) => {
|
|||
*/
|
||||
const handleActive = () => {
|
||||
if (!_selectedRowKeys.value.length) {
|
||||
return onlyMessage('请选择数据', 'warning');
|
||||
return onlyMessage('请选择数据', 'warning');
|
||||
}
|
||||
if (
|
||||
_selectedRowKeys.value.length >= 10 &&
|
||||
|
@ -809,7 +848,10 @@ const handleActive = () => {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
onlyMessage('仅支持同一个运营商下且最少10条数据,最多100条数据', 'warning');
|
||||
onlyMessage(
|
||||
'仅支持同一个运营商下且最少10条数据,最多100条数据',
|
||||
'warning',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -827,7 +869,10 @@ const handleStop = () => {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
onlyMessage('仅支持同一个运营商下且最少10条数据,最多100条数据', 'warning');
|
||||
onlyMessage(
|
||||
'仅支持同一个运营商下且最少10条数据,最多100条数据',
|
||||
'warning',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -845,7 +890,10 @@ const handleResumption = () => {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
onlyMessage('仅支持同一个运营商下且最少10条数据,最多100条数据', 'warning');
|
||||
onlyMessage(
|
||||
'仅支持同一个运营商下且最少10条数据,最多100条数据',
|
||||
'warning',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -869,7 +917,9 @@ const handelRemove = async () => {
|
|||
onlyMessage('请选择数据', 'error');
|
||||
return;
|
||||
}
|
||||
const resp = await removeCards(_selectedRowKeys.value.map( v => ({ id:v })));
|
||||
const resp = await removeCards(
|
||||
_selectedRowKeys.value.map((v) => ({ id: v })),
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功');
|
||||
_selectedRowKeys.value = [];
|
||||
|
@ -962,10 +1012,10 @@ const batchActions: BatchActionsType[] = [
|
|||
];
|
||||
|
||||
onMounted(() => {
|
||||
if (routerParams.params.value.type === 'add' && paltformPermission) {
|
||||
handleAdd()
|
||||
}
|
||||
})
|
||||
if (routerParams.params.value.type === 'add' && paltformPermission) {
|
||||
handleAdd();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -50,15 +50,15 @@
|
|||
<div class="item-english">物联卡</div>
|
||||
<div class="item-content">
|
||||
<div
|
||||
v-for="iten in pieChartData"
|
||||
:key="iten.key"
|
||||
v-for="item in pieChartData"
|
||||
:key="item.key"
|
||||
class="item-node"
|
||||
>
|
||||
<div class="item-node-text">
|
||||
{{ iten.value }}
|
||||
{{ item.value }}
|
||||
</div>
|
||||
<div :class="`state ${iten.className}`">
|
||||
{{ iten.name }}
|
||||
<div :class="`state ${item.className}`">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -159,7 +159,7 @@ const barChartData = ref<any[]>([]);
|
|||
const pieChartData = ref<any[]>([
|
||||
{
|
||||
key: 'using',
|
||||
name: '正常',
|
||||
name: '激活',
|
||||
value: 0,
|
||||
className: 'normal',
|
||||
},
|
||||
|
|
|
@ -122,7 +122,7 @@ const columns = [
|
|||
},
|
||||
{
|
||||
title: '接入方式',
|
||||
dataIndex: 'accessName',
|
||||
dataIndex: 'accessId',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
search: {
|
||||
|
@ -192,12 +192,14 @@ const columns = [
|
|||
hideInTable: true,
|
||||
search: {
|
||||
type: 'treeSelect',
|
||||
termOptions: ['eq'],
|
||||
componentProps: {
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
value: 'value',
|
||||
},
|
||||
},
|
||||
|
||||
options: () => new Promise((resolve) => {
|
||||
getTreeData_api({ paging: false }).then((resp: any) => {
|
||||
const formatValue = (list: any[]) => {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
@mouseout='mouseout'
|
||||
>
|
||||
<j-popconfirm
|
||||
title='该操作将清空其它所有否则条件,确认删除?'
|
||||
title='该操作将清空过滤条件,确认删除?'
|
||||
placement="topRight"
|
||||
@confirm='onDeleteAll'
|
||||
>
|
||||
|
@ -156,7 +156,7 @@ const WarpClass = computed(() => {
|
|||
|
||||
const onDelete = () => {
|
||||
if (FormModel.value.branches?.length == 2) {
|
||||
FormModel.value.branches?.splice(props.name, 1, null)
|
||||
FormModel.value.branches?.splice(props.name, 1)
|
||||
} else {
|
||||
FormModel.value.branches?.splice(props.name, 1)
|
||||
}
|
||||
|
@ -164,8 +164,8 @@ const onDelete = () => {
|
|||
|
||||
const onDeleteAll = () => {
|
||||
if (FormModel.value.branches) {
|
||||
FormModel.value.branches.length = props.name
|
||||
FormModel.value.branches.push(null as any)
|
||||
FormModel.value.branches[props.name].when = []
|
||||
FormModel.value.options.when[props.branches_Index].terms = []
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -287,7 +287,6 @@ watchEffect(() => {
|
|||
activeKey.value = _group[0].id
|
||||
}
|
||||
}
|
||||
console.log(group.value,'group')
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
|
@ -461,7 +461,7 @@ const uploader: uploaderType = {
|
|||
if (!typeBool) {
|
||||
onlyMessage(`请上传.jpg.png.jfif.pjp.pjpeg.jpeg格式的图片`, 'error');
|
||||
} else if (!sizeBool) {
|
||||
onlyMessage(`图片大小必须小于2M`, 'error');
|
||||
onlyMessage(`图片大小必须小于4M`, 'error');
|
||||
}
|
||||
return typeBool && sizeBool;
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue