fix: 替换vue3-markdown-it为markdown-it

* fix: 替换vue3-markdown-it为markdown-it
This commit is contained in:
XieYongHong 2024-04-24 14:39:44 +08:00 committed by GitHub
parent f75d40f223
commit 926cc90cd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 3353 additions and 4327 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 || [];

View File

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

View File

@ -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%'} });
}
};

View File

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

1
src/global.d.ts vendored
View File

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

View File

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

View File

@ -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(二进制)'
);
});

View File

@ -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')" />

View File

@ -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 = () => {

View File

@ -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);
}

View File

@ -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) => { //

View File

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

View File

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

View File

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

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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',
},

View File

@ -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[]) => {

View File

@ -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 = []
}
}

View File

@ -287,7 +287,6 @@ watchEffect(() => {
activeKey.value = _group[0].id
}
}
console.log(group.value,'group')
})
</script>

View File

@ -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;
},

6432
yarn.lock

File diff suppressed because it is too large Load Diff