fix: 优化第三方应用菜单集成

* fix: 优化第三方应用菜单集成

* fix: bug#20731

* fix: 修改lodash依赖包

* fix: bug#20731
This commit is contained in:
XieYongHong 2023-12-04 16:36:59 +08:00 committed by GitHub
parent feb8dcddb9
commit 9ba07046e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 570 additions and 232 deletions

View File

@ -25,7 +25,7 @@
"event-source-polyfill": "^1.0.31", "event-source-polyfill": "^1.0.31",
"global": "^4.4.0", "global": "^4.4.0",
"jetlinks-store": "^0.0.3", "jetlinks-store": "^0.0.3",
"jetlinks-ui-components": "^1.0.34-7", "jetlinks-ui-components": "^1.0.34-12",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",
"less": "^4.1.3", "less": "^4.1.3",

View File

@ -10,11 +10,23 @@ import zhCN from 'jetlinks-ui-components/es/locale/zh_CN';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useSystem } from './store/system'; import { useSystem } from './store/system';
import DefaultSetting from '../config/config' import DefaultSetting from '../config/config'
import {LocalStore} from "@/utils/comm";
import {TOKEN_KEY} from "@/utils/variable";
const system = useSystem(); const system = useSystem();
const {configInfo} = storeToRefs(system); const {configInfo} = storeToRefs(system);
system.setDocumentTitle() system.setDocumentTitle()
const route = useRoute()
watch(() => JSON.stringify(route.query || {}), () => {
if (route.query.token) {
LocalStore.set(TOKEN_KEY, route.query.token);
}
}, { immediate: true })
ConfigProvider.config({ ConfigProvider.config({
theme: { theme: {
primaryColor: "#315efb" primaryColor: "#315efb"

View File

@ -21,5 +21,3 @@ export const saveMenuInfo_api = (data: object) => server.patch(`/menu`, data);
export const addMenuInfo_api = (data: object) => server.post(`/menu`, data); export const addMenuInfo_api = (data: object) => server.post(`/menu`, data);
// 删除菜单信息 // 删除菜单信息
export const delMenuInfo_api = (id: string) => server.remove(`/menu/${id}`); export const delMenuInfo_api = (id: string) => server.remove(`/menu/${id}`);
//查询集成菜单
export const queryApp = (data:any) => server.post('/application/_query/no-paging',data)

View File

@ -4,8 +4,8 @@
v-model:collapsed="basicLayout.collapsed" v-model:collapsed="basicLayout.collapsed"
v-model:openKeys="basicLayout.openKeys" v-model:openKeys="basicLayout.openKeys"
:selectedKeys="basicLayout.selectedKeys" :selectedKeys="basicLayout.selectedKeys"
:headerHeight='layout.headerHeight' :breadcrumb="basicLayout.pure ? undefined : { routes: breadcrumbs }"
:breadcrumb="{ routes: breadcrumbs }" :headerHeight='basicLayout.pure ? 1 : layout.headerHeight'
:pure="basicLayout.pure" :pure="basicLayout.pure"
@backClick='routerBack' @backClick='routerBack'
> >

View File

@ -159,11 +159,11 @@ const extraRouteObj = {
type Buttons = Array<{ id: string }> type Buttons = Array<{ id: string }>
const hasAppID = (item: any): { isApp: boolean, appUrl: string } => { const hasAppID = (item: any): { isApp: boolean, appUrl: string } => {
const isApp = !!item.appId const isApp = !!item.appId || item.options?.owner
const isLowCode = !!item.options?.LowCode const isLowCode = !!item.options?.LowCode
return { return {
isApp: isApp || isLowCode, isApp: isApp || isLowCode,
appUrl: isApp ? `/${item.appId}${item.url}` : item.url appUrl: isApp ? `/${item.appId || item.options?.owner}${item.url}` : item.url
} }
} }

View File

@ -149,7 +149,7 @@ import { StatusColorEnum, updateStatus } from './data';
import { useMenuStore } from 'store/menu'; import { useMenuStore } from 'store/menu';
import Save from './Save/index.vue'; import Save from './Save/index.vue';
import { protocolList } from '@/utils/consts'; import { protocolList } from '@/utils/consts';
import _ from 'lodash'; import _ from 'lodash-es';
const menuStory = useMenuStore(); const menuStory = useMenuStore();
const tableRef = ref<Record<string, any>>({}); const tableRef = ref<Record<string, any>>({});

View File

@ -87,7 +87,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { FormInstance } from 'ant-design-vue'; import type { FormInstance } from 'ant-design-vue';
import { savePointBatch } from '@/api/data-collect/collector'; import { savePointBatch } from '@/api/data-collect/collector';
import { cloneDeep, isObject } from 'lodash'; import { cloneDeep, isObject } from 'lodash-es';
import { regOnlyNumber } from '../../../data'; import { regOnlyNumber } from '../../../data';
const props = defineProps({ const props = defineProps({

View File

@ -148,7 +148,7 @@ import {
} from '@/api/data-collect/collector'; } from '@/api/data-collect/collector';
import Save from './Save/index.vue'; import Save from './Save/index.vue';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import _ from 'lodash'; import _ from 'lodash-es';
import { colorMap } from '../data.ts'; import { colorMap } from '../data.ts';
const props = defineProps({ const props = defineProps({

View File

@ -481,7 +481,7 @@ import {
getAliyunProductsList, getAliyunProductsList,
queryProductList, queryProductList,
} from '@/api/northbound/alicloud'; } from '@/api/northbound/alicloud';
import _ from 'lodash'; import _ from 'lodash-es';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import MSelect from '../../components/MSelect/index.vue'; import MSelect from '../../components/MSelect/index.vue';
import { _deploy } from '@/api/device/product'; import { _deploy } from '@/api/device/product';

View File

@ -546,7 +546,7 @@ import {
savePatch, savePatch,
detail, detail,
} from '@/api/northbound/dueros'; } from '@/api/northbound/dueros';
import _, { cloneDeep } from 'lodash'; import _, { cloneDeep } from 'lodash-es';
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import MSelect from '../../components/MSelect/index.vue'; import MSelect from '../../components/MSelect/index.vue';

View File

@ -60,7 +60,6 @@ const queryTypeList = () => {
if (!user.other.tabKey) { if (!user.other.tabKey) {
user.other.tabKey = arr?.[0]?.provider; user.other.tabKey = arr?.[0]?.provider;
} }
tabs.value = arr; tabs.value = arr;
} }
}); });
@ -70,6 +69,17 @@ watchEffect(() => {
if (router.params.value?.other?.tabKey) { if (router.params.value?.other?.tabKey) {
user.other.tabKey = router.params.value?.other?.tabKey user.other.tabKey = router.params.value?.other?.tabKey
} }
if(router.params?.value.row){
if(['device-transparent-codec'].includes(router.params?.value.row.topicProvider)){
user.other.tabKey = 'system-business'
}
if(['system-event'].includes(router.params?.value.row.topicProvider)){
user.other.tabKey = 'system-monitor'
}
if(['workflow-task-cc','workflow-task-todo','workflow-task-reject', 'workflow-process-finish', 'workflow-process-repealed','workflow-task-transfer-todo'].includes(router.params?.value.row.topicProvider)){
user.other.tabKey = 'workflow-notification'
}
}
}); });
onMounted(() => { onMounted(() => {

View File

@ -74,7 +74,7 @@
import type { ActionsType } from '@/components/Table/index'; import type { ActionsType } from '@/components/Table/index';
import { query, queryProduct, remove } from '@/api/device/firmware'; import { query, queryProduct, remove } from '@/api/device/firmware';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import _ from 'lodash'; import _ from 'lodash-es';
import Save from './Save/index.vue'; import Save from './Save/index.vue';
import { useMenuStore } from 'store/menu'; import { useMenuStore } from 'store/menu';
import type { FormDataType } from './type'; import type { FormDataType } from './type';

View File

@ -57,7 +57,7 @@ import { map } from 'rxjs/operators';
import { useInstanceStore } from '@/store/instance'; import { useInstanceStore } from '@/store/instance';
import { getWebSocket } from '@/utils/websocket'; import { getWebSocket } from '@/utils/websocket';
import { randomString } from '@/utils/utils'; import { randomString } from '@/utils/utils';
import _ from 'lodash'; import _ from 'lodash-es';
const message = reactive<MessageType>({ const message = reactive<MessageType>({
up: { up: {

View File

@ -49,7 +49,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useInstanceStore } from '@/store/instance'; import { useInstanceStore } from '@/store/instance';
import _ from 'lodash'; import _ from 'lodash-es';
import { saveTags, delTags } from '@/api/device/instance' import { saveTags, delTags } from '@/api/device/instance'
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';

View File

@ -160,7 +160,7 @@ import {
delDeviceCode, queryCodeTips, queryProductCodeTips, delDeviceCode, queryCodeTips, queryProductCodeTips,
} from '@/api/device/instance'; } from '@/api/device/instance';
import { message } from 'jetlinks-ui-components'; import { message } from 'jetlinks-ui-components';
import { isBoolean } from 'lodash'; import { isBoolean } from 'lodash-es';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
const defaultValue = const defaultValue =

View File

@ -30,7 +30,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useInstanceStore } from '@/store/instance'; import { useInstanceStore } from '@/store/instance';
import _ from 'lodash'; import _ from 'lodash-es';
import Event from './Event/index.vue'; import Event from './Event/index.vue';
import Property from './Property/index.vue'; import Property from './Property/index.vue';

View File

@ -119,7 +119,7 @@ import {
testCode, testCode,
saveProductCode, queryProductCodeTips, saveProductCode, queryProductCodeTips,
} from '@/api/device/instance'; } from '@/api/device/instance';
import { isBoolean } from 'lodash'; import { isBoolean } from 'lodash-es';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
const defaultValue = const defaultValue =

View File

@ -300,7 +300,7 @@ import 'driver.js/dist/driver.min.css';
import { marked } from 'marked'; import { marked } from 'marked';
import type { TableColumnType } from 'ant-design-vue'; import type { TableColumnType } from 'ant-design-vue';
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
import _ from 'lodash'; import _ from 'lodash-es';
import { accessConfigTypeFilter } from '@/utils/setting'; import { accessConfigTypeFilter } from '@/utils/setting';
import AccessModal from './accessModal.vue' import AccessModal from './accessModal.vue'
import MetaDataModal from './metadataModal.vue' import MetaDataModal from './metadataModal.vue'

View File

@ -190,14 +190,13 @@ import {
updateDevice, updateDevice,
} from '@/api/device/product'; } from '@/api/device/product';
import { isNoCommunity, downloadObject } from '@/utils/utils'; import { isNoCommunity, downloadObject } from '@/utils/utils';
import { omit } from 'lodash-es'; import { omit , cloneDeep } from 'lodash-es';
import { typeOptions } from '@/components/Search/util'; import { typeOptions } from '@/components/Search/util';
import Save from './Save/index.vue'; import Save from './Save/index.vue';
import { useMenuStore } from 'store/menu'; import { useMenuStore } from 'store/menu';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useRouterParams } from '@/utils/hooks/useParams'; import { useRouterParams } from '@/utils/hooks/useParams';
import { accessConfigTypeFilter } from '@/utils/setting'; import { accessConfigTypeFilter } from '@/utils/setting';
import {cloneDeep} from "lodash";
/** /**
* 表格数据 * 表格数据
*/ */

View File

@ -1,5 +1,6 @@
<template> <template>
<j-data-table <j-data-table
v-if="!heavyLoad"
ref="tableRef" ref="tableRef"
:data-source="dataSource" :data-source="dataSource"
:columns="columns" :columns="columns"
@ -12,7 +13,7 @@
@change="(data) => dataSourceCache = data" @change="(data) => dataSourceCache = data"
> >
<template #expand> <template #expand>
<PermissionButton <!-- <PermissionButton
type="primary" type="primary"
v-if="!showSave" v-if="!showSave"
:hasPermission="`${permission}:update`" :hasPermission="`${permission}:update`"
@ -30,14 +31,12 @@
placement="topRight" placement="topRight"
> >
新增 新增
</PermissionButton> </PermissionButton> -->
<PermissionButton <PermissionButton
type="primary" type="primary"
:hasPermission="`${permission}:update`" :hasPermission="`${permission}:update`"
key="update" key="update"
v-else
:loading="loading" :loading="loading"
:disabled="hasOperate('add', type) || !editStatus" :disabled="hasOperate('add', type) || !editStatus"
:tooltip="{ :tooltip="{
title: hasOperate('add', type) title: hasOperate('add', type)
@ -203,6 +202,26 @@
</j-space> </j-space>
</template> </template>
</j-data-table> </j-data-table>
<PermissionButton
type="primary"
block
ghost
:hasPermission="`${permission}:update`"
key="add"
:disabled="hasOperate('add', type)"
:tooltip="{
placement: hasOperate('add', type) ? 'topRight' : 'top',
title: hasOperate('add', type)
? '当前的存储方式不支持新增'
: '新增',
getPopupContainer: getPopupContainer,
}"
@click="handleAddClick()"
placement="topRight"
>
<template #icon><AIcon type="PlusOutlined"/></template>
新增行
</PermissionButton>
<PropertiesModal <PropertiesModal
v-if="type === 'properties' && detailData.visible" v-if="type === 'properties' && detailData.visible"
:data="detailData.data" :data="detailData.data"
@ -250,16 +269,16 @@ import { asyncUpdateMetadata, updateMetadata } from '../metadata';
import { useMetadataStore } from '@/store/metadata'; import { useMetadataStore } from '@/store/metadata';
import { DeviceInstance } from '@/views/device/Instance/typings'; import { DeviceInstance } from '@/views/device/Instance/typings';
import { onlyMessage , LocalStore} from '@/utils/comm'; import { onlyMessage , LocalStore} from '@/utils/comm';
import {omit} from "lodash-es"; import { omit , cloneDeep} from "lodash-es";
import { PropertiesModal, FunctionModal, EventModal, TagsModal } from './DetailModal' import { PropertiesModal, FunctionModal, EventModal, TagsModal } from './DetailModal'
import { Modal } from 'jetlinks-ui-components' import { Modal } from 'jetlinks-ui-components'
import {EventEmitter} from "@/utils/utils"; import {EventEmitter} from "@/utils/utils";
import {computed, watch} from "vue"; import {computed, watch} from "vue";
import {cloneDeep} from "lodash";
import {useSystem} from "store/system"; import {useSystem} from "store/system";
import {storeToRefs} from "pinia"; import {storeToRefs} from "pinia";
import { FULL_CODE } from 'jetlinks-ui-components/es/DataTable' import { FULL_CODE } from 'jetlinks-ui-components/es/DataTable'
import { usePermissionStore } from '@/store/permission'; import { usePermissionStore } from '@/store/permission';
import App from '@/App.vue';
const props = defineProps({ const props = defineProps({
target: { target: {
@ -278,6 +297,7 @@ const props = defineProps({
const _target = inject<'device' | 'product'>('_metadataType', props.target); const _target = inject<'device' | 'product'>('_metadataType', props.target);
const tableContainer = ref()
const system = useSystem(); const system = useSystem();
const {basicLayout} = storeToRefs(system); const {basicLayout} = storeToRefs(system);
const router = useRouter() const router = useRouter()
@ -303,7 +323,7 @@ const detailData = reactive({
visible:false visible:false
}) })
const heavyLoad = ref<Boolean>(false)
const showSave = ref(metadata.value.length !== 0) const showSave = ref(metadata.value.length !== 0)
@ -402,6 +422,11 @@ const handleAddClick = async (_data?: any, index?: number) => {
const newObject = _data || getDataByType() const newObject = _data || getDataByType()
const _addData = await tableRef.value.addItem(newObject, index) const _addData = await tableRef.value.addItem(newObject, index)
nextTick(()=>{
if(tableContainer.value.classList.value === 'tableContainer'){
tableContainer.value.classList.remove('tableContainer')
}
})
// if (_addData.length === 1) { // if (_addData.length === 1) {
// showLastDelete.value = true // showLastDelete.value = true
// } // }
@ -424,7 +449,6 @@ const removeItem = (index: number) => {
// } // }
if (_data.length === 0) { if (_data.length === 0) {
showSave.value = false showSave.value = false
handleSaveClick() handleSaveClick()
} }
} }

View File

@ -71,7 +71,7 @@ import { EventLevel, ExpandsTypeList } from '@/views/device/data';
import { useMetadataStore } from '@/store/metadata'; import { useMetadataStore } from '@/store/metadata';
import { validateJson } from './validator'; import { validateJson } from './validator';
import { Rule } from 'ant-design-vue/es/form'; import { Rule } from 'ant-design-vue/es/form';
import { debounce } from 'lodash'; import { debounce } from 'lodash-es';
const props = defineProps({ const props = defineProps({
type: { type: {

View File

@ -21,7 +21,7 @@ import { DeviceInstance } from '@/views/device/Instance/typings';
import BaseForm from './BaseForm.vue'; import BaseForm from './BaseForm.vue';
import { PropType } from 'vue'; import { PropType } from 'vue';
import { _deploy } from '@/api/device/product'; import { _deploy } from '@/api/device/product';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash-es';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
const props = defineProps({ const props = defineProps({

View File

@ -41,7 +41,7 @@ import { reactive } from 'vue';
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import Item from './item.vue' import Item from './item.vue'
import {Form} from "jetlinks-ui-components"; import {Form} from "jetlinks-ui-components";
import {cloneDeep} from "lodash"; import { cloneDeep } from "lodash-es";
import { FULL_CODE } from 'jetlinks-ui-components/es/DataTable' import { FULL_CODE } from 'jetlinks-ui-components/es/DataTable'
import dayjs from "dayjs"; import dayjs from "dayjs";

View File

@ -68,12 +68,11 @@
<script setup lang="ts" name="OtherSetting"> <script setup lang="ts" name="OtherSetting">
import Metrics from './Metrics/Metrics.vue' import Metrics from './Metrics/Metrics.vue'
import {watch} from "vue"; import {watch} from "vue";
import {cloneDeep} from "lodash";
import {useProductStore} from "store/product"; import {useProductStore} from "store/product";
import {useInstanceStore} from "store/instance"; import {useInstanceStore} from "store/instance";
import {getMetadataConfig, getMetadataDeviceConfig} from "@/api/device/product"; import {getMetadataConfig, getMetadataDeviceConfig} from "@/api/device/product";
import ModelButton from '@/views/device/components/Metadata/Base/components/ModelButton.vue' import ModelButton from '@/views/device/components/Metadata/Base/components/ModelButton.vue'
import {omit} from "lodash-es"; import { omit , cloneDeep} from "lodash-es";
import { FULL_CODE } from 'jetlinks-ui-components/es/DataTable' import { FULL_CODE } from 'jetlinks-ui-components/es/DataTable'
const props = defineProps({ const props = defineProps({

View File

@ -33,8 +33,7 @@ import type { Key } from 'ant-design-vue/es/_util/type';
import { convertMetadata, getCodecs, detail as productDetail } from '@/api/device/product'; import { convertMetadata, getCodecs, detail as productDetail } from '@/api/device/product';
import { detail } from '@/api/device/instance' import { detail } from '@/api/device/instance'
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import {cloneDeep} from "lodash"; import { omit , cloneDeep } from "lodash-es";
import {omit} from "lodash-es";
interface Props { interface Props {
visible: boolean; visible: boolean;

View File

@ -4,7 +4,7 @@
<iframe <iframe
v-if="loading" v-if="loading"
:src="iframeUrl" :src="iframeUrl"
scrolling="no" scrolling="yes"
frameBorder="0" frameBorder="0"
style="width: 100%; height: 100%" style="width: 100%; height: 100%"
></iframe> ></iframe>
@ -48,17 +48,18 @@ const handle = async (appId: string, url: string) => {
} }
} }
const _url = menuUrl.startsWith('/') ? menuUrl : `/${menuUrl}`;
if (result.provider === 'internal-standalone') { if (result.provider === 'internal-standalone') {
const urlStandalone = `${result.page.baseUrl}/api/application/sso/${appId}/login?redirect=${menuUrl}?layout=false`; const urlStandalone = `${result.page.baseUrl}/api/application/sso/${appId}/login?redirect=${menuUrl}?layout=false`;
iframeUrl.value = urlStandalone; iframeUrl.value = urlStandalone;
} else if (result.provider === 'internal-integrated') { } else if (result.provider === 'internal-integrated') {
const _url = menuUrl.startsWith('/') ? menuUrl : `/${menuUrl}`;
const tokenUrl = `${ const tokenUrl = `${
result.page.baseUrl result.page.baseUrl
}${_url}?layout=false&X-Access-Token=${LocalStore.get(TOKEN_KEY)}`; }${_url}?layout=false&X-Access-Token=${LocalStore.get(TOKEN_KEY)}`;
iframeUrl.value = tokenUrl; iframeUrl.value = tokenUrl;
} else { } else {
const urlOther = `${result.page.baseUrl}/${menuUrl}`; const urlOther = `${result.page.baseUrl}${_url}`;
iframeUrl.value = urlOther; iframeUrl.value = urlOther;
} }
} }
@ -106,6 +107,7 @@ watchEffect(() => {
} else { } else {
loading.value = true loading.value = true
const url = route.path.split('/').slice(2).join('/'); const url = route.path.split('/').slice(2).join('/');
console.log(route.path.split('/').slice(2))
handle(params, url); handle(params, url);
} }
} }

View File

@ -40,9 +40,14 @@ const getProvidersFn = async () => {
if (version ==='community') { if (version ==='community') {
return undefined return undefined
} else { } else {
try {
const res: any = await getProviders(); const res: any = await getProviders();
const ids = res.result?.map?.(item => item.id) || [] const ids = res.result?.map?.(item => item.id) || []
return protocolList.some(item => ids.includes(item.value)) return protocolList.some(item => ids.includes(item.value))
} catch (error) {
return false
}
} }
} }

View File

@ -146,7 +146,7 @@ import { getImage } from '@/utils/comm';
import { list, remove } from '@/api/link/protocol'; import { list, remove } from '@/api/link/protocol';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import Save from './Save/index.vue'; import Save from './Save/index.vue';
import _ from 'lodash'; import _ from 'lodash-es';
const tableRef = ref<Record<string, any>>({}); const tableRef = ref<Record<string, any>>({});
const params = ref<Record<string, any>>({}); const params = ref<Record<string, any>>({});

View File

@ -29,7 +29,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { debounce } from 'lodash'; import { debounce } from 'lodash-es';
import ChannelApi from '@/api/media/channel'; import ChannelApi from '@/api/media/channel';
import DeviceApi from '@/api/media/device'; import DeviceApi from '@/api/media/device';

View File

@ -80,7 +80,7 @@ import Tag from './Tag.vue';
import RelationSelect from './RelationSelect.vue'; import RelationSelect from './RelationSelect.vue';
import { getParams } from '../../../util'; import { getParams } from '../../../util';
import { handleParamsData } from '../../../components/Terms/util'; import { handleParamsData } from '../../../components/Terms/util';
import _ from 'lodash'; import _ from 'lodash-es';
const props = defineProps({ const props = defineProps({
values: { values: {

View File

@ -193,7 +193,7 @@ const handOptionByColumn = (option: any) => {
] ]
} }
} else if(option.type === 'enum') { } else if(option.type === 'enum') {
valueOptions.value = _options?.map((item: any) => ({ ...item, label: item.name, value: item.id})) || [] valueOptions.value = _options?.elements?.map((item: any) => ({ ...item, label: item.text, value: item.value})) || []
} else{ } else{
valueOptions.value = _options?.map((item: any) => ({ ...item, label: item.name, value: item.id})) || [] valueOptions.value = _options?.map((item: any) => ({ ...item, label: item.name, value: item.id})) || []
} }

View File

@ -127,7 +127,7 @@ const dropdownButtonClass = computed(() => ({
const treeSelect = (v: any, option: any) => { const treeSelect = (v: any, option: any) => {
const node = option.node const node = option.node
visible.value = false visible.value = false
label.value = node.fullname || node.name label.value = node.fullName || node.name
selectValue.value = v[0] selectValue.value = v[0]
emit('update:value', node[props.valueName]) emit('update:value', node[props.valueName])
emit('select', node) emit('select', node)

View File

@ -82,8 +82,7 @@ import { ContextKey, arrayParamsKey, timeTypeKeys } from './util'
import { useSceneStore } from 'store/scene' import { useSceneStore } from 'store/scene'
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { Form } from 'jetlinks-ui-components' import { Form } from 'jetlinks-ui-components'
import {indexOf, isArray, isObject, isString, pick} from 'lodash-es' import {indexOf, isArray, isObject, isString, pick , cloneDeep } from 'lodash-es'
import {cloneDeep} from "lodash";
const sceneStore = useSceneStore() const sceneStore = useSceneStore()
const { data: formModel } = storeToRefs(sceneStore) const { data: formModel } = storeToRefs(sceneStore)

View File

@ -1428,7 +1428,7 @@ import { getImage, onlyMessage } from '@/utils/comm';
import type { formType, dictType, optionsType, applyType } from '../typing'; import type { formType, dictType, optionsType, applyType } from '../typing';
import { getRoleList_api } from '@/api/system/user'; import { getRoleList_api } from '@/api/system/user';
import { randomString } from '@/utils/utils'; import { randomString } from '@/utils/utils';
import { cloneDeep, difference } from 'lodash'; import { cloneDeep, difference } from 'lodash-es';
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
import { Rule } from 'ant-design-vue/lib/form'; import { Rule } from 'ant-design-vue/lib/form';
import ApplyList from './ApplyList/index.vue'; import ApplyList from './ApplyList/index.vue';

View File

@ -49,6 +49,7 @@ const handleOk = async () => {
...form.checkedMenu, ...form.checkedMenu,
// ...form.half, // ...form.half,
]); ]);
dealMenu(items)
console.log(items); console.log(items);
if (form.checkedSystem) { if (form.checkedSystem) {
if (items && items.length !== 0) { if (items && items.length !== 0) {
@ -169,6 +170,17 @@ function getSystemList(id: string) {
}); });
} }
const dealMenu = (data:any)=>{
data?.forEach((i:any)=>{
i.options = {
show:true
}
if(i.children){
dealMenu(i.children)
}
})
}
watch(() => props.data, (newVal: any) => { watch(() => props.data, (newVal: any) => {
form.checkedSystem = newVal?.page.configuration?.checkedSystem form.checkedSystem = newVal?.page.configuration?.checkedSystem
if (form.checkedSystem) { if (form.checkedSystem) {

View File

@ -1,150 +1,456 @@
<template> <template>
<j-modal <j-modal
:confirmLoading="loading"
class="edit-dialog-container" class="edit-dialog-container"
title="集成菜单" title="集成菜单"
visible visible
width="600px" width="800px"
:maskClosable="false"
@cancel="cancel" @cancel="cancel"
@ok="handleOk" @ok="cancel"
> >
<p> <div style="display: flex;">
当前集成菜单 <div class="menuList" >
</p> 菜单列表
<div class="content">
<PermissionButton
type="link"
:hasPermission="`${permission}:add`"
@click="addMenu"
>
+ 新增菜单
</PermissionButton>
<div class="treeContainer">
<j-tree <j-tree
v-if="menuTree.length" :fieldNames="{
v-model:checkedKeys="menuState.checkedMenu" title:'name',
v-model:expandedKeys="menuState.expandedKeys" key:'id',
:fieldNames="{ key: 'code', title: 'name' }" children:'children'
:height="300" }"
:tree-data="menuTree" :treeData="treeData"
checkable >
/> <template #title="data">
<j-empty <div class="tree-item">
v-else <div class="title">
/> <j-ellipsis>{{ data.name }}</j-ellipsis>
</div>
<div class="menuControls">
<PermissionButton
v-if="data.options?.owner"
type="link"
:hasPermission="`${permission}:update`"
tooltip="编辑"
@click="()=>editMenu(data)"
>
<AIcon type="EditOutlined" />
</PermissionButton>
<PermissionButton
type="link"
:hasPermission="`${permission}:add`"
:tooltip="{ title: data.level >= 3 ? '仅支持3级菜单' : '新增子菜单' }"
:disabled="data.level >= 3 || data.options?.LowCode"
@click="()=>addChildrenMenu(data)"
>
<AIcon type="PlusCircleOutlined" />
</PermissionButton>
<PermissionButton
v-if="data.options?.owner"
type="link"
:hasPermission="`${permission}:delete`"
tooltip="删除"
:popConfirm="{
title: `是否删除该菜单`,
onConfirm: () => deleteMenu(data),
}"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</div>
</div>
</template>
</j-tree>
</div>
</div>
</div>
<div class="configuration" v-if="showControls">
菜单配置
<div class="content">
<div class="saveBtn">
<PermissionButton type="primary" :hasPermission="`${permission}:${ editType === 'add' ? 'add' : 'update'
}`" :loading='saveLoading' @click="saveMenu">
保存
</PermissionButton>
</div>
<j-form ref="basicFormRef" :model="formData" class="basic-form" layout="vertical">
<div class="row" style="display: flex">
<j-form-item ref="uploadIcon" label="菜单图标" name="icon" :rules="[
{
required: true,
message: '请上传图标',
trigger: 'change',
},
]" style="flex: 0 0 186px">
<div class="icon-upload has-icon" v-if="formData.icon">
<AIcon :type="formData.icon" style="font-size: 90px" />
<span class="mark" @click="dialogVisible = true">点击修改</span>
</div>
<div v-else @click="dialogVisible = true" class="icon-upload no-icon">
<span>
<AIcon type="PlusOutlined" style="font-size: 30px" />
<p>点击选择图标</p>
</span>
</div>
</j-form-item>
<j-row>
<j-col :span="24">
<j-form-item label="名称" name="name" :rules="[
{
required: true,
message: '请输入名称',
},
{
max: 64,
message: '最多可输入64个字符',
},
]">
<j-input v-model:value="formData.name" placeholder="请输入名称" />
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item label="编码" name="code" :validateFirst="true" :rules="[
{
required: true,
message: '请输入编码',
},
{
max: 64,
message: '最多可输入64个字符',
},
{
validator: checkCode,
trigger: 'blur',
},
]">
<j-input v-model:value="formData.code" placeholder="请输入编码" />
</j-form-item>
</j-col>
<!-- <j-col :span="12">
<j-form-item label="排序" name="sortIndex" :rules="[
{
pattern: /^[0-9]*[1-9][0-9]*$/,
message: '请输入大于0的整数',
},
]">
<j-input-number v-model:value="formData.sortIndex" placeholder="请输入排序"
style="width: 100%" />
</j-form-item>
</j-col> -->
</j-row>
</div>
<j-form-item label="页面地址" name="url" :validateFirst="true" :rules="[
{
required: true,
message: '请输入页面地址',
},
{ max: 128, message: '最多可输入128个字符'},
{ pattern: /^\//, message: '请正确填写地址,以/开头' },
]">
<j-input v-model:value="formData.url" placeholder="请输入页面地址" />
</j-form-item>
<!-- <j-form-item label="说明" name="describe">
<j-textarea v-model:value="formData.describe" :rows="4" show-count :maxlength="200"
placeholder="请输入说明" />
</j-form-item> -->
</j-form>
</div>
</div>
</div>
<ChooseIconDialog v-if="dialogVisible" v-model:visible="dialogVisible" :icon="formData.icon"
@confirm="(typeStr: string) => choseIcon(typeStr)" />
</j-modal> </j-modal>
</template> </template>
<script name="ThirdMenu" setup> <script name="ThirdMenu" setup lang="ts">
import {getMenuTree_api, queryOwnThree} from '@/api/system/menu'; import { getMenuTree_api , validCode_api , addMenuInfo_api ,saveMenuInfo_api , getMenuInfo_api , delMenuInfo_api} from '@/api/system/menu'
import { USER_CENTER_MENU_CODE,messageSubscribe } from '@/utils/consts'
import ChooseIconDialog from '../../Menu/components/ChooseIconDialog.vue'
import { Rule } from 'ant-design-vue/lib/form';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import { useRequest } from '@/hook'
import {filterTree, getCheckByTree} from "@/views/system/Apply/componenets/util";
import {
saveOwnerMenu_api,
updateApp_api,
} from '@/api/system/apply';
const props = defineProps({ const props = defineProps({
mode: {
type: String,
default: 'add'
},
data: { data: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
} }
}) })
const emit = defineEmits(['cancel'])
const menuStory = useMenuStore(); const permission = 'system/Menu';
const loading = ref(false) const basicFormRef = ref()
const emit = defineEmits(['ok', 'cancel']); const treeData = ref([])
const menuState = reactive({ const formData = ref<any>({
checkedMenu: [], icon:'',
expandedKeys: [], name:'',
menuTree: '' code:'',
url:'',
sortIndex:0
}) })
const sourceCode = ref()
const menuTree = computed(() => { const dialogVisible = ref(false)
try { const uploadIcon = ref()
return JSON.parse(menuState.menuTree || '[]') const showControls = ref(false)
} catch (e) { const editType = ref()
return [] const saveLoading = ref(false)
} const rootMenuTotal = ref<Number>(0)
}) const queryParams = {
sorts: [{ name: 'sortIndex', order: 'asc' }],
useRequest(queryOwnThree, paging: false,
{
defaultParams: { terms: [{ column: 'owner', termType: 'isnull', value: 0 }]},
onSuccess(res) {
menuState.menuTree = JSON.stringify(res.result)
return res
}
}
)
const { run } = useRequest(getMenuTree_api, {
immediate: false,
onSuccess(res) {
menuState.checkedMenu = getCheckByTree(res.result)
return res
}
}) //
const cancel = () => {
if (props.mode === 'add') {
menuStory.jumpPage('system/Apply/Save', {}, { id: props.data?.id })
}
emit('cancel')
}
const handleOk = async () => {
if (!menuState.checkedMenu.length) {
onlyMessage('请勾选配置菜单', 'warning')
return
}
const id = props.data.id
const cloneData = JSON.parse(menuState.menuTree)
const filterData = filterTree(cloneData, menuState.checkedMenu)
loading.value = true
try {
const resp = await saveOwnerMenu_api('iot', id, filterData)
await updateApp_api(id, {
...props.data,
integrationModes: props.data?.integrationModes?.map((item) => item?.value || item),
page: {
...props.data?.page,
configuration: {
checkedSystem: props.data?.page?.configuration?.checkedSystem
}
}
})
if (resp.success) {
//
onlyMessage('操作成功');
emit('ok')
}
loading.value = false
} catch (e) {
console.log(e)
loading.value = false
}
}
const getBindMenuData = () => {
const id = props.data.id
run({
terms: [ terms: [
{ {
column: 'appId', terms: [
value: id, {
column: 'owner',
termType: 'eq',
value: 'iot',
},
{
column: 'owner',
termType: 'isnull',
value: '1',
type: 'or',
}, },
], ],
},
{
terms:[
{
terms:[
{
value:"%show\":true%",
termType:"like",
column:"options",
type:'and'
},
{
value:"%owner\"%",
termType:"nlike",
column:"options",
type:"and"
}
]
},
{
terms:[
{
value:`%owner\":\"${props.data.id}%`,
termType:"like",
column:"options"
}
],
type:"or"
}
]
}
],
}
const addChildrenMenu = (data:any) =>{
basicFormRef.value?.clearValidate()
initFormData()
showControls.value = true
editType.value = 'add'
formData.value.parentId = data?.id
formData.value.url = data?.url
formData.value.sortIndex = data?.children?.length + 1|| 0;
}
const addMenu = () =>{
initFormData()
formData.value.sortIndex = rootMenuTotal.value
sourceCode.value = ''
showControls.value = true
editType.value = 'add'
}
const editMenu = (data:any) =>{
basicFormRef.value?.clearValidate()
initFormData()
showControls.value = true
editType.value = 'edit'
getMenuInfo_api(data.id).then((res:any)=>{
formData.value = res.result
sourceCode.value = res.result?.code
}) })
} }
const deleteMenu = (data:any) =>{
if (props.data?.id) { delMenuInfo_api(data.id).then((resp: any) => {
getBindMenuData() if (resp.status === 200) {
onlyMessage('操作成功');
queryMenu();
}
});
} }
const initFormData = () =>{
formData.value = {
icon:'',
name:'',
code:'',
url:'',
}
}
const choseIcon = (typeStr: string) => {
formData.value.icon = typeStr;
uploadIcon.value?.clearValidate();
}
const saveMenu = () =>{
basicFormRef.value.validate().then(()=>{
const api = editType.value === 'add' ? addMenuInfo_api : saveMenuInfo_api
saveLoading.value = true
const params ={
...formData.value,
owner: 'iot',
options: { show: true ,owner:props.data?.id },
}
api(params).then((res)=>{
if(res.status === 200){
onlyMessage('操作成功')
queryMenu()
}else{
onlyMessage('操作失败')
}
}).finally(() => (saveLoading.value = false));
})
}
const checkCode = async (_rule: Rule, value: string): Promise<any> => {
if (!value) return Promise.reject('');
else if (value.length > 64) return Promise.reject('最多可输入64个字符');
//
else if (editType.value = 'edit' && value === sourceCode.value)
return Promise.resolve('');
else {
const resp: any = await validCode_api({
code: value,
owner: 'iot',
});
if (resp.result.passed) return Promise.resolve();
else return Promise.reject('该编码重复');
}
}
const cancel = () =>{
emit('cancel')
}
const queryMenu = () =>{
getMenuTree_api(queryParams).then((res:any)=>{
treeData.value = res.result?.filter((item: { code: string }) => ![USER_CENTER_MENU_CODE,messageSubscribe].includes(item.code))
const lastItem = res.result[res.result.length - 1];
rootMenuTotal.value = lastItem ? lastItem.sortIndex + 1 : 1;
})
}
onMounted(()=>{
queryMenu()
})
</script> </script>
<style scoped> <style lang="less" scoped>
.menuList{
width: 35%;
margin-right: 20px;
}
.configuration{
width: 60%;
}
.content{
border: .3px solid rgb(220, 220, 220);
position: relative;
.saveBtn{
position: absolute;
right: 20px;
top: 10px;
}
.basic-form{
height: 432px;
padding: 32px 20px;
:deep(.ant-form-item-control-input-content) {
.icon-upload {
width: 160px;
height: 150px;
border: 1px dashed #d9d9d9;
font-size: 14px;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
cursor: pointer;
transition: 0.5s;
&:hover {
border-color: #415ed1;
}
}
.has-icon {
position: relative;
text-align: center;
.mark {
position: absolute;
left: 0;
top: 0;
display: none;
background-color: rgba(0, 0, 0, 0.35);
color: #fff;
width: 100%;
height: 100%;
font-size: 16px;
align-items: center;
justify-content: center;
}
&:hover .mark {
display: flex;
}
}
.no-icon {
background-color: rgba(0, 0, 0, 0.06);
}
}
}
.treeContainer{
height: 400px;
overflow-y: auto;
}
.tree-item{
display: flex;
position: relative;
align-items: stretch;
justify-content: space-around;
.title {
flex: 1;
min-width: 80px;
margin-right: 80px;
}
.menuControls {
position: absolute;
right: 10px;
display: none;
font-size: 14px;
:deep(.ant-btn-link) {
padding: 0 4px;
height: 24px;
}
}
}
}
:deep(.ant-tree-treenode) {
width: 100%;
.ant-tree-node-content-wrapper {
flex: 1 1 auto;
}
.ant-tree-title {
&:hover {
.menuControls{
display: block;
}
}
}
}
</style> </style>

View File

@ -312,7 +312,8 @@ const tableRef = ref();
const current = ref<any>({}) const current = ref<any>({})
const table = { const table = {
refresh: () => { refresh: () => {
tableRef.value.reload(queryParams.value); // tableRef.value.reload(queryParams.value);
window.location.reload()
}, },
toAdd: () => { toAdd: () => {
visible.value = true visible.value = true

View File

@ -235,8 +235,7 @@ import { onlyMessage } from '@/utils/comm';
import { randomString } from '@/utils/utils'; import { randomString } from '@/utils/utils';
import { FormInstance } from 'ant-design-vue'; import { FormInstance } from 'ant-design-vue';
import { DataNode } from 'ant-design-vue/lib/tree'; import { DataNode } from 'ant-design-vue/lib/tree';
import _ from 'lodash'; import _ , { cloneDeep } from 'lodash-es';
import { cloneDeep } from 'lodash';
import type { dbColumnType, dictItemType, sourceItemType } from '../typing'; import type { dbColumnType, dictItemType, sourceItemType } from '../typing';
const id = useRoute().query.id as string; const id = useRoute().query.id as string;

View File

@ -255,7 +255,6 @@ init();
width: 100%; width: 100%;
} }
} }
:deep(.ant-tree-treenode) { :deep(.ant-tree-treenode) {
width: 100%; width: 100%;
.ant-tree-node-content-wrapper { .ant-tree-node-content-wrapper {
@ -278,7 +277,7 @@ init();
flex: 1 1 auto; flex: 1 1 auto;
.department-tree-item-content { .department-tree-item-content {
display: flex; display: flex;
align-items: center; align-items: stretch;
.title { .title {
flex: 1; flex: 1;

View File

@ -61,14 +61,14 @@
</j-form-item> </j-form-item>
</j-col> </j-col>
<j-col :span="12"> <j-col :span="12">
<j-form-item label="页面地址" name="url" :rules="[ <j-form-item :rules="[
{ {
required: true, required: true,
message: '请输入页面地址', message: '请输入页面地址',
}, },
{ max: 128, message: '最多可输入128字符' }, { max: 128, message: '最多可输入128字符' },
{ pattern: /^\//, message: '请正确填写地址,以/开头' }, { pattern: /^\//, message: '请正确填写地址,以/开头' },
]"> ]" :validateFirst="true" label="页面地址" name="url">
<j-input v-model:value="form.data.url" placeholder="请输入页面地址" /> <j-input v-model:value="form.data.url" placeholder="请输入页面地址" />
</j-form-item> </j-form-item>
</j-col> </j-col>
@ -83,12 +83,6 @@
style="width: 100%" /> style="width: 100%" />
</j-form-item> </j-form-item>
</j-col> </j-col>
<j-col :span="12" v-if="!isChildren">
<j-form-item label="所属应用" name="appId">
<j-select v-model:value="form.data.appId" :options="appOptions" :allowClear="!routeParams.id"
placeholder="请选择所属应用" style="width: 100%" @change="selectApp"/>
</j-form-item>
</j-col>
</j-row> </j-row>
</div> </div>
@ -98,7 +92,7 @@
</j-form-item> </j-form-item>
</j-form> </j-form>
</div> </div>
<div class="card" v-if="!form.data.appId && !isChildren"> <div class="card" v-if="!form.data.appId">
<h3>权限配置</h3> <h3>权限配置</h3>
<j-form ref="permissFormRef" :model="form.data" class="basic-form permiss-form"> <j-form ref="permissFormRef" :model="form.data" class="basic-form permiss-form">
<j-form-item name="accessSupport" required v-if="isNoCommunity"> <j-form-item name="accessSupport" required v-if="isNoCommunity">
@ -172,12 +166,11 @@ import {
saveMenuInfo_api, saveMenuInfo_api,
addMenuInfo_api, addMenuInfo_api,
validCode_api, validCode_api,
queryApp
} from '@/api/system/menu'; } from '@/api/system/menu';
import { Rule } from 'ant-design-vue/lib/form'; import { Rule } from 'ant-design-vue/lib/form';
import { isNoCommunity } from '@/utils/utils'; import { isNoCommunity } from '@/utils/utils';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { applicationInfo } from '@/api/bind';
const permission = 'system/Menu'; const permission = 'system/Menu';
// //
@ -189,7 +182,6 @@ const routeParams = {
url: route.query.basePath, url: route.query.basePath,
parentId: route.query.pid, parentId: route.query.pid,
}; };
const isChildren = route.query?.isChildren
// //
const basicFormRef = ref<FormInstance>(); const basicFormRef = ref<FormInstance>();
const permissFormRef = ref<FormInstance>(); const permissFormRef = ref<FormInstance>();
@ -207,8 +199,6 @@ const form = reactive({
accessSupport: 'unsupported', accessSupport: 'unsupported',
assetType: undefined, assetType: undefined,
indirectMenus: [], indirectMenus: [],
appId: '',
application:'',
...routeParams, ...routeParams,
} as formType, } as formType,
treeData: [], // treeData: [], //
@ -290,9 +280,6 @@ const form = reactive({
: '间接控制', : '间接控制',
}, },
}; };
if(params?.isChildren){
delete params.isChildren
}
api(params) api(params)
.then((resp: any) => { .then((resp: any) => {
if (resp.status === 200) { if (resp.status === 200) {
@ -320,32 +307,9 @@ const choseIcon = (typeStr: string) => {
form.data.icon = typeStr; form.data.icon = typeStr;
uploadIcon.value?.clearValidate(); uploadIcon.value?.clearValidate();
} }
const selectApp = (value:string,options:any) =>{
form.data.application = options?.label
}
// //
const dialogVisible = ref(false); const dialogVisible = ref(false);
onMounted(() => {
queryApp({
terms: [
{
"column": "integrationModes",
"termType": "in$any",
"value": "page"
}
],
paging: false
}).then((res:any)=>{
appOptions.value = res.result?.map((i:any)=>{
return {
label:i.name,
value:i.id
}
})
})
})
type formType = { type formType = {
id?: string; id?: string;
name: string; name: string;
@ -359,8 +323,6 @@ type formType = {
assetType: string | undefined; assetType: string | undefined;
indirectMenus: any[]; indirectMenus: any[];
parentId?: string; parentId?: string;
appId:string,
application:string
}; };
type assetType = { type assetType = {

View File

@ -76,7 +76,7 @@ import {
} from './utils'; } from './utils';
import BaseMenu from '@/views/init-home/data/baseMenu'; import BaseMenu from '@/views/init-home/data/baseMenu';
import type { AntTreeNodeDropEvent } from 'ant-design-vue/es/tree'; import type { AntTreeNodeDropEvent } from 'ant-design-vue/es/tree';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash-es';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { import {
USER_CENTER_MENU_CODE, USER_CENTER_MENU_CODE,

View File

@ -3,6 +3,7 @@
visible visible
title="菜单图标" title="菜单图标"
width="800px" width="800px"
:maskClosable="false"
@cancel="emits('update:visible', false)" @cancel="emits('update:visible', false)"
@ok="confirm" @ok="confirm"
> >

View File

@ -131,7 +131,7 @@ import { JsonViewer } from 'vue3-json-viewer';
import 'vue3-json-viewer/dist/index.css'; import 'vue3-json-viewer/dist/index.css';
import type { apiDetailsType } from '../typing'; import type { apiDetailsType } from '../typing';
import InputCard from './InputCard.vue'; import InputCard from './InputCard.vue';
import { cloneDeep, toLower } from 'lodash'; import { cloneDeep, toLower } from 'lodash-es';
import { FormInstance } from 'ant-design-vue'; import { FormInstance } from 'ant-design-vue';
import server from '@/utils/request'; import server from '@/utils/request';
import { findData, getCodeText } from '../utils'; import { findData, getCodeText } from '../utils';

View File

@ -107,6 +107,7 @@ const columns = [
ellipsis: true, ellipsis: true,
fixed: 'left', fixed: 'left',
search: { search: {
rename:'objectType',
type: 'select', type: 'select',
options: async () =>{ options: async () =>{
const res:any = await getObjectList_api() const res:any = await getObjectList_api()

View File

@ -147,7 +147,10 @@
{ {
validator: form.rules.checkUserName, validator: form.rules.checkUserName,
trigger: 'blur', trigger: 'blur',
}, },{
validator: form.rules.checkCh,
trigger: 'change'
}
]" ]"
> >
<j-input <j-input
@ -189,6 +192,9 @@
validator: form.rules.checkAgainPassword, validator: form.rules.checkAgainPassword,
trigger: 'blur', trigger: 'blur',
}, },
{
}
]" ]"
> >
<j-input-password <j-input-password
@ -261,10 +267,14 @@ const form = reactive({
data: {} as formType, data: {} as formType,
rules: { rules: {
checkCh: (_rule:Rule,value:string): Promise<any> =>
new Promise((resolve,reject) => {
if (/[\u4e00-\u9fa5]/.test(value)) return reject('用户名不能包含中文');
else return resolve('')
}),
checkUserName: (_rule: Rule, value: string): Promise<any> => checkUserName: (_rule: Rule, value: string): Promise<any> =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
if (props.type === 'edit') return resolve(''); if (props.type === 'edit') return resolve('');
if (!value) return reject('请输入用户名'); if (!value) return reject('请输入用户名');
else if (value.length > 64) return reject('最多可输入64个字符'); else if (value.length > 64) return reject('最多可输入64个字符');
validateField_api('username', value).then((resp: any): any => { validateField_api('username', value).then((resp: any): any => {

View File

@ -3738,10 +3738,10 @@ jetlinks-store@^0.0.3:
resolved "https://registry.npmjs.org/jetlinks-store/-/jetlinks-store-0.0.3.tgz" resolved "https://registry.npmjs.org/jetlinks-store/-/jetlinks-store-0.0.3.tgz"
integrity sha512-AZf/soh1hmmwjBZ00fr1emuMEydeReaI6IBTGByQYhTmK1Zd5pQAxC7WLek2snRAn/HHDgJfVz2hjditKThl6Q== integrity sha512-AZf/soh1hmmwjBZ00fr1emuMEydeReaI6IBTGByQYhTmK1Zd5pQAxC7WLek2snRAn/HHDgJfVz2hjditKThl6Q==
jetlinks-ui-components@^1.0.34-7: jetlinks-ui-components@^1.0.34-12:
version "1.0.34-7" version "1.0.34-12"
resolved "https://registry.npmjs.org/jetlinks-ui-components/-/jetlinks-ui-components-1.0.34-7.tgz#3a14e85edb4c5d11427d30f3925dc5f498478940" resolved "https://registry.npmjs.org/jetlinks-ui-components/-/jetlinks-ui-components-1.0.34-12.tgz#13e035bae1d16af957d81a175daaa3a2fe290406"
integrity sha512-Rgbjig3QYP8CDVHLbco20Cf7sArYralO8yWtH5E5zylYAN2lINLUsgOlIVf9aweszZR/Ps+z/NLP0CoRQf1Xtw== integrity sha512-fxoncKov8IsScneXQYcaBwg+HnXrkJSaS7z9aV7uZK4/WxvTaAWozOPIOSkBwfDya+BuRpbJ9ZW3X9MtT6kLrQ==
dependencies: dependencies:
"@vueuse/core" "^9.12.0" "@vueuse/core" "^9.12.0"
"@vueuse/router" "^9.13.0" "@vueuse/router" "^9.13.0"