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

This commit is contained in:
wangshuaiswim 2023-04-01 14:55:11 +08:00
commit 76a880b130
39 changed files with 623 additions and 180 deletions

View File

@ -9,7 +9,7 @@ export const updateMeInfo_api = (data:object) => server.put(`/user/detail`,data)
// 修改登录用户密码 // 修改登录用户密码
export const updateMepsd_api = (data:object) => server.put(`/user/passwd`,data); export const updateMepsd_api = (data:object) => server.put(`/user/passwd`,data);
// 第三方账号解绑 // 第三方账号解绑
export const unBind_api = (appId: string) => server.post(`/application/sso/${appId}/unbind/me`); export const unBind_api = (appId: string) => server.post(`/application/sso/${appId}/unbind/me`, []);
/** /**
* *
* @param type * @param type

View File

@ -67,6 +67,14 @@
</j-upload> </j-upload>
</template> </template>
</j-input> </j-input>
<j-input
v-else-if="typeMap.get(itemType) === 'password'"
allowClear
type="password"
v-model:value="myValue"
style="width: 100%"
@change='inputChange'
/>
<j-input <j-input
v-else v-else
allowClear allowClear
@ -148,7 +156,7 @@ const componentsType = ref<ITypes>({
double: 'inputNumber', double: 'inputNumber',
string: 'input', string: 'input',
array: 'input', array: 'input',
password: 'input', password: 'password',
enum: 'select', enum: 'select',
boolean: 'select', boolean: 'select',
date: 'date', date: 'date',

View File

@ -2,6 +2,8 @@ export const LoginPath = '/login'
export const InitHomePath = '/init-home' export const InitHomePath = '/init-home'
export const AccountCenterBindPath = '/account/center/bind' export const AccountCenterBindPath = '/account/center/bind'
export const InitLicense = '/init-license' export const InitLicense = '/init-license'
export const NotificationSubscriptionCode = 'account/NotificationSubscription'
export const NotificationRecordCode = 'account/NotificationRecord'
export const AccountMenu = { export const AccountMenu = {
path: '/account', path: '/account',

View File

@ -1,11 +1,12 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { queryOwnThree } from '@/api/system/menu' import { queryOwnThree } from '@/api/system/menu'
import { filterAsyncRouter, findCodeRoute, MenuItem } from '@/utils/menu' import { filterAsyncRouter, findCodeRoute, MenuItem } from '@/utils/menu'
import { isArray } from 'lodash-es' import { cloneDeep, isArray } from 'lodash-es'
import { usePermissionStore } from './permission' import { usePermissionStore } from './permission'
import router from '@/router' import router from '@/router'
import { onlyMessage } from '@/utils/comm' import { onlyMessage } from '@/utils/comm'
import { AccountMenu } from '@/router/menu' import { AccountMenu, NotificationRecordCode, NotificationSubscriptionCode } from '@/router/menu'
import { MESSAGE_SUBSCRIBE_MENU_CODE, USER_CENTER_MENU_CODE } from '@/utils/consts'
const defaultOwnParams = [ const defaultOwnParams = [
{ {
@ -96,6 +97,13 @@ export const useMenuStore = defineStore({
const permission = usePermissionStore() const permission = usePermissionStore()
permission.permissions = {} permission.permissions = {}
const { menusData, silderMenus } = filterAsyncRouter(resp.result) const { menusData, silderMenus } = filterAsyncRouter(resp.result)
// 是否存在通知订阅
const hasMessageSub = resp.result.some((item: { code: string }) => item.code === MESSAGE_SUBSCRIBE_MENU_CODE)
console.log('hasMessageSub', hasMessageSub)
if (!hasMessageSub) {
AccountMenu.children = AccountMenu.children.filter((item: { code: string }) => ![NotificationSubscriptionCode, NotificationRecordCode].includes(item.code) )
}
this.menus = findCodeRoute([...resp.result, AccountMenu]) this.menus = findCodeRoute([...resp.result, AccountMenu])
Object.keys(this.menus).forEach((item) => { Object.keys(this.menus).forEach((item) => {
const _item = this.menus[item] const _item = this.menus[item]
@ -112,7 +120,7 @@ export const useMenuStore = defineStore({
} }
}) })
menusData.push(AccountMenu) menusData.push(AccountMenu)
this.siderMenus = silderMenus this.siderMenus = silderMenus.filter((item: { name: string }) => ![USER_CENTER_MENU_CODE, MESSAGE_SUBSCRIBE_MENU_CODE].includes(item.name))
res(menusData) res(menusData)
} }
}) })

View File

@ -1,3 +1,5 @@
import { MESSAGE_SUBSCRIBE_MENU_DATA } from '@/views/init-home/data/baseMenu'
/** /**
* *
*/ */
@ -47,3 +49,8 @@ export const SystemConst = {
VERSION_CODE: 'version_code', VERSION_CODE: 'version_code',
AMAP_KEY : 'amap_key', AMAP_KEY : 'amap_key',
} }
export const USER_CENTER_MENU_CODE = 'account-center'
export const USER_CENTER_MENU_BUTTON_CODE = 'user-center-passwd-update'
export const MESSAGE_SUBSCRIBE_MENU_CODE = 'message-subscribe'
export const MESSAGE_SUBSCRIBE_MENU_BUTTON_CODE = 'message-subscribe-view'

View File

@ -330,11 +330,13 @@ const handleOk = async () => {
if (data?.configuration.function !== 'HoldingRegisters') { if (data?.configuration.function !== 'HoldingRegisters') {
codec.provider = 'int8'; codec.provider = 'int8';
} }
const { interval } = formData.value.configuration;
const params = { const params = {
...props.data, ...props.data,
...data, ...data,
provider, provider,
collectorId, collectorId,
interval,
}; };
// addressreact使 // addressreact使
@ -413,23 +415,17 @@ const filterOption = (input: string, option: any) => {
const getProviderList = async () => { const getProviderList = async () => {
const res: any = await queryCodecProvider(); const res: any = await queryCodecProvider();
providerListAll.value = res.result providerListAll.value = res.result
.filter((i: any) => i.id !== 'property') .filter((i: any) => i.id !== 'property' && i.id !== 'bool')
.map((item: any) => ({ .map((item: any) => ({
value: item.id, value: item.id,
label: item.name, label: item.name,
})); }));
setProviderList(formData.value.configuration.function); setProviderList(formData.value.configuration.function);
}; };
getProviderList(); getProviderList();
const setProviderList = (value: string | undefined) => { const setProviderList = (value: string | undefined) => {
providerList.value = providerList.value = providerListAll.value;
value === 'HoldingRegisters'
? providerListAll.value
: providerListAll.value.filter(
(item: any) => item.value !== 'bool',
);
}; };
watch( watch(

View File

@ -132,11 +132,13 @@ const formData = ref({
const handleOk = async () => { const handleOk = async () => {
const data = await formRef.value?.validate(); const data = await formRef.value?.validate();
const { interval } = formData.value.configuration;
const params = { const params = {
...props.data, ...props.data,
...data, ...data,
provider, provider,
collectorId, collectorId,
interval,
}; };
loading.value = true; loading.value = true;

View File

@ -101,7 +101,7 @@ const formRef = ref<FormInstance>();
const formData = ref({ const formData = ref({
accessModes: [], accessModes: [],
interval: '', interval: undefined,
features: [], features: [],
}); });
@ -118,7 +118,10 @@ const handleOk = async () => {
const data = cloneDeep(formData.value); const data = cloneDeep(formData.value);
const { accessModes, features, interval } = data; const { accessModes, features, interval } = data;
const ischange = const ischange =
accessModes.length !== 0 || features.length !== 0 || !!interval; accessModes.length !== 0 ||
features.length !== 0 ||
Number(interval) === 0 ||
!!interval;
if (ischange) { if (ischange) {
const params = cloneDeep(props.data); const params = cloneDeep(props.data);
params.forEach((i: any) => { params.forEach((i: any) => {
@ -132,7 +135,7 @@ const handleOk = async () => {
} }
} }
features.length !== 0 && (i.features = data.features); features.length !== 0 && (i.features = data.features);
if (!!interval) { if (!!interval || Number(interval) === 0) {
i.interval = data.interval; i.interval = data.interval;
i.configuration = { i.configuration = {
...i.configuration, ...i.configuration,

View File

@ -281,9 +281,14 @@
<span>{{ <span>{{
getText(slotProps) getText(slotProps)
}}</span> }}</span>
<span>{{ <span
v-if="
getInterval(slotProps) getInterval(slotProps)
}}</span> "
>{{
getInterval(slotProps)
}}</span
>
</div> </div>
</Ellipsis> </Ellipsis>
</div> </div>
@ -334,7 +339,7 @@ import SaveModBus from './Save/SaveModBus.vue';
import SaveOPCUA from './Save/SaveOPCUA.vue'; import SaveOPCUA from './Save/SaveOPCUA.vue';
import Scan from './Scan/index.vue'; import Scan from './Scan/index.vue';
import { colorMap } from '../data.ts'; import { colorMap } from '../data.ts';
import { cloneDeep, isNumber } from 'lodash-es'; import { cloneDeep, isNumber, throttle } from 'lodash-es';
import { getWebSocket } from '@/utils/websocket'; import { getWebSocket } from '@/utils/websocket';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@ -616,17 +621,6 @@ const handleClick = (dt: any) => {
} }
}; };
//
let timer: any = null;
function throttle(fn: any, delay = 1000) {
if (timer == null) {
timer = setTimeout(() => {
fn();
clearTimeout(timer);
timer = null;
}, delay);
}
}
const subscribeProperty = (value: any) => { const subscribeProperty = (value: any) => {
const list = value.map((item: any) => item.id); const list = value.map((item: any) => item.id);
const id = `collector-${props.data?.channelId || 'channel'}-${ const id = `collector-${props.data?.channelId || 'channel'}-${
@ -643,7 +637,7 @@ const subscribeProperty = (value: any) => {
// //
throttle(() => { throttle(() => {
propertyValue.value.set(payload.pointId, payload); propertyValue.value.set(payload.pointId, payload);
}); }, 1000);
}); });
}; };

View File

@ -107,11 +107,7 @@
/> />
</j-form-item> </j-form-item>
<div style="color: #616161" v-if="visibleEndian"> <div style="color: #616161" v-if="visibleEndian">
<p> <p>当前内存布局: {{ endianData }}</p>
当前内存布局:{{
endianMap.get(formData.configuration.endian)
}}{{ endianMap.get(formData.configuration.endianIn) }}
</p>
<p> <p>
只有4字节数据类型(int32ieee754 float) 只有4字节数据类型(int32ieee754 float)
具有4种内存布局其它只有ABCDDCBA两种内存布局(以双字配置为准) 具有4种内存布局其它只有ABCDDCBA两种内存布局(以双字配置为准)
@ -182,10 +178,21 @@ const emit = defineEmits(['change']);
const id = props.data.id; const id = props.data.id;
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
const endianMap = new Map([
['BIG', 'AB'], const endianData = computed(() => {
['LITTLE', 'BA'], const { endian, endianIn } = formData.value.configuration;
]); if (endian) {
if (endianIn) {
if (endian === 'BIG') {
return endianIn === 'BIG' ? 'ABCD' : 'BADC';
} else {
return endianIn === 'BIG' ? 'CDBA' : 'DCBA';
}
} else {
return endian === 'BIG' ? 'ABCD' : 'DCBA';
}
}
});
const formData = ref({ const formData = ref({
channelId: undefined, channelId: undefined,

View File

@ -310,6 +310,9 @@ watch(
:deep(.ant-tree-list-holder-inner) { :deep(.ant-tree-list-holder-inner) {
width: 90%; width: 90%;
} }
:deep(.ant-tree-list) {
width: 110%;
}
:deep(.ant-tree-treenode) { :deep(.ant-tree-treenode) {
width: 100%; width: 100%;

View File

@ -110,7 +110,7 @@
/> />
</div> </div>
</div> </div>
<div class="card"> <div class="card" v-if='updatePassword'>
<h3>修改密码</h3> <h3>修改密码</h3>
<div class="content"> <div class="content">
<div class="content" style="align-items: flex-end"> <div class="content" style="align-items: flex-end">
@ -245,7 +245,10 @@ import moment from 'moment';
import { getMe_api, getView_api, setView_api } from '@/api/home'; import { getMe_api, getView_api, setView_api } from '@/api/home';
import { isNoCommunity } from '@/utils/utils'; import { isNoCommunity } from '@/utils/utils';
import { userInfoType } from './typing'; import { userInfoType } from './typing';
import { usePermissionStore } from 'store/permission'
const btnHasPermission = usePermissionStore().hasPermission;
const updatePassword = btnHasPermission('account-center:user-center-passwd-update')
const permission = 'system/User'; const permission = 'system/User';
const userInfo = ref<userInfoType>({} as any); const userInfo = ref<userInfoType>({} as any);
// //
@ -361,7 +364,7 @@ function getViews() {
.then((resp: any) => { .then((resp: any) => {
if (resp?.status === 200) { if (resp?.status === 200) {
if (resp.result) currentView.value = resp.result?.content; if (resp.result) currentView.value = resp.result?.content;
else if (resp.result.username === 'admin') { else if (resp.result?.username === 'admin') {
currentView.value = 'comprehensive'; currentView.value = 'comprehensive';
} else currentView.value = 'init'; } else currentView.value = 'init';
} }

View File

@ -56,7 +56,10 @@ watch(
() => user.userInfos, () => user.userInfos,
(val: any) => { (val: any) => {
// //
if (val.username === 'admin') selectValue.value = 'comprehensive'; if (val.username === 'admin') {
selectValue.value = 'comprehensive';
confirm();
}
}, },
); );
</script> </script>

View File

@ -12,7 +12,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { getImage } from '@/utils/comm'; import { getImage } from '@/utils/comm';
import BaseMenu from '../data/baseMenu'; import BaseMenu, { MESSAGE_SUBSCRIBE_MENU_DATA, USER_CENTER_MENU_DATA } from '../data/baseMenu'
import { getSystemPermission, updateMenus } from '@/api/initHome'; import { getSystemPermission, updateMenus } from '@/api/initHome';
/** /**
* 获取菜单数据 * 获取菜单数据
@ -70,7 +70,8 @@ const menuCount = (menus: any[]) => {
*/ */
const initMenu = async () => { const initMenu = async () => {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
const res = await updateMenus(menuDatas.current); //
const res = await updateMenus([...menuDatas.current!, USER_CENTER_MENU_DATA, MESSAGE_SUBSCRIBE_MENU_DATA]);
if (res.status === 200) { if (res.status === 200) {
resolve(true); resolve(true);
} else { } else {

View File

@ -1,3 +1,55 @@
import {
MESSAGE_SUBSCRIBE_MENU_BUTTON_CODE,
MESSAGE_SUBSCRIBE_MENU_CODE,
USER_CENTER_MENU_BUTTON_CODE,
USER_CENTER_MENU_CODE
} from '@/utils/consts'
export const USER_CENTER_MENU_DATA = {
id: '19a1f2c763e1231f1e1',
accessSupport: { value: 'unsupported', label: '不支持'},
supportDataAccess: false,
code: USER_CENTER_MENU_CODE,
name: '个人中心',
url: '/user-center',
sortIndex: 9999,
granted: true,
buttons: [
{
id: USER_CENTER_MENU_BUTTON_CODE,
name: '修改密码',
permissions: [
{
permission: 'user',
action: ['update-self-pwd']
}
]
}
]
}
export const MESSAGE_SUBSCRIBE_MENU_DATA = {
id: '23a1f2c7123e56731f890',
accessSupport: { value: 'unsupported', label: '不支持'},
supportDataAccess: false,
code: MESSAGE_SUBSCRIBE_MENU_CODE,
name: '通知订阅',
url: '/message-subscribe',
buttons: [
{
id: MESSAGE_SUBSCRIBE_MENU_BUTTON_CODE,
name: '查看',
permissions: [
{
permission: 'alarm-config',
action: ['query']
}
]
}
],
sortIndex: 9998
}
export default [ export default [
// 物联网 // 物联网
{ {
@ -4015,6 +4067,10 @@ export default [
permission: 'network-card', permission: 'network-card',
actions: ['save'], actions: ['save'],
}, },
{
permission: 'device-instance',
actions: ['query'],
},
], ],
}, },
{ {
@ -4218,5 +4274,5 @@ export default [
supportDataAccess: false supportDataAccess: false
}, },
], ],
}, }
]; ];

View File

@ -134,18 +134,14 @@ const submitData = async () => {
* 判断是否已有配置 * 判断是否已有配置
*/ */
const judgeInitSet = async () => { const judgeInitSet = async () => {
if (userInfo.$state.userInfos.username === 'admin') {
const resp: any = await getInit(); const resp: any = await getInit();
if (resp.status === 200 && resp.result.length) { if (resp.status === 200 && resp.result.length) {
window.location.href = '/'; window.location.href = '/';
} }
} else {
window.location.href = '/';
}
}; };
onMounted(() => { onBeforeMount(() => {
judgeInitSet(); // judgeInitSet();
}); })
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.page-container { .page-container {

View File

@ -70,6 +70,7 @@
import { queryPlatformNoPage, recharge } from '@/api/iot-card/cardManagement'; import { queryPlatformNoPage, recharge } from '@/api/iot-card/cardManagement';
import { message } from 'jetlinks-ui-components'; import { message } from 'jetlinks-ui-components';
import { PaymentMethod } from '@/views/iot-card/data'; import { PaymentMethod } from '@/views/iot-card/data';
import { onlyMessage } from '@/utils/comm'
const emit = defineEmits(['change', 'save']); const emit = defineEmits(['change', 'save']);
@ -168,6 +169,8 @@ const handleOk = () => {
if (resp.status === 200) { if (resp.status === 200) {
if (resp.result === '失败') { if (resp.result === '失败') {
message.error('缴费失败') message.error('缴费失败')
} else if(!resp.result) {
onlyMessage('操作过于频繁,请稍后再试!', 'warning')
} else { } else {
window.open(resp.result); window.open(resp.result);
} }

View File

@ -161,7 +161,7 @@ const saveChange = (val: any) => {
if (val) { if (val) {
setTimeout(() => { setTimeout(() => {
rechargeRef.value?.reload(); rechargeRef.value?.reload();
}, 500) }, 700)
} }
}; };

View File

@ -654,7 +654,7 @@ const saveData = () => {
onlyMessage('操作成功', 'success'); onlyMessage('操作成功', 'success');
if (route.query.save) { if (route.query.save) {
// @ts-ignore // @ts-ignore
window?.onTabSaveSuccess(resp.result); window?.onTabSaveSuccess(resp);
window.close(); window.close();
} else { } else {
history.back(); history.back();

View File

@ -315,7 +315,7 @@ const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
text: '删除', text: '删除',
disabled: state === 'enabled', disabled: state === 'enabled',
tooltip: { tooltip: {
title: state === 'enabled' ? '已启用的设备不能删除' : '删除', title: state === 'enabled' ? '请先禁用,再删除' : '删除',
}, },
popConfirm: { popConfirm: {
title: '确认删除?', title: '确认删除?',

View File

@ -1365,11 +1365,23 @@ const getDetail = () => {
...cloneDeep(Configuration), /// ...cloneDeep(Configuration), ///
...configuration, ...configuration,
}; };
const configRef = Store.get('configRef').filter(
(item: any) => item.host === '0.0.0.0',
);
getPortOptions(configRef); //
} else { } else {
dynamicValidateForm.cluster = { dynamicValidateForm.cluster = cluster;
...cloneDeep(FormStates2), // //
...cluster, setTimeout(() => {
}; cluster.forEach((item: any, index: number) => {
const { host } = item.configuration;
let configRef = Store.get('configRef').filter(
(item: any) => item.host === host,
);
getPortOptions(configRef, index);
});
}, 0);
} }
if (dynamicValidateForm.cluster.length === 1) { if (dynamicValidateForm.cluster.length === 1) {

View File

@ -319,9 +319,9 @@ const handleAdd = () => {
const tab: any = window.open( const tab: any = window.open(
`${origin}/#/iot/link/accessConfig/detail/:id?save=true&view=false&type=${props.channel}`, `${origin}/#/iot/link/accessConfig/detail/:id?save=true&view=false&type=${props.channel}`,
); );
tab.onTabSaveSuccess = async (value: string) => { tab.onTabSaveSuccess = async (value: any) => {
await getGatewayList(); await getGatewayList();
handleClick(value); handleClick(value?.result);
}; };
}; };
</script> </script>

View File

@ -159,6 +159,7 @@ const paramsValue = reactive<TermsType>({
const formItemContext = Form.useInjectFormItemContext() const formItemContext = Form.useInjectFormItemContext()
const showDelete = ref(false) const showDelete = ref(false)
const columnOptions: any = inject('filter-params') // const columnOptions: any = inject('filter-params') //
const columnType = ref<string>()
const termTypeOptions = ref<Array<{ id: string, name: string}>>([]) // const termTypeOptions = ref<Array<{ id: string, name: string}>>([]) //
const valueOptions = ref<any[]>([]) // const valueOptions = ref<any[]>([]) //
const arrayParamsKey = ['nbtw', 'btw', 'in', 'nin', 'contains_all', 'contains_any', 'not_contains'] const arrayParamsKey = ['nbtw', 'btw', 'in', 'nin', 'contains_all', 'contains_any', 'not_contains']
@ -175,6 +176,7 @@ const handOptionByColumn = (option: any) => {
if (option) { if (option) {
termTypeOptions.value = option.termTypes || [] termTypeOptions.value = option.termTypes || []
tabsOptions.value[0].component = option.type tabsOptions.value[0].component = option.type
columnType.value = option.type
const _options = isArray(option.options) ? option.options : [] const _options = isArray(option.options) ? option.options : []
if (option.type === 'boolean') { if (option.type === 'boolean') {
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})) || [
@ -289,6 +291,7 @@ const termsTypeSelect = (e: { key: string, name: string }) => {
let value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue let value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
// timeTypeKeys // timeTypeKeys
if (columnType.value ==='date') {
if (timeTypeKeys.includes(e.key)) { if (timeTypeKeys.includes(e.key)) {
if (tabsOptions.value[0].component !== 'int') { if (tabsOptions.value[0].component !== 'int') {
value = undefined value = undefined
@ -298,6 +301,7 @@ const termsTypeSelect = (e: { key: string, name: string }) => {
value = undefined value = undefined
tabsOptions.value[0].component = 'date' tabsOptions.value[0].component = 'date'
} }
}
paramsValue.value = { paramsValue.value = {
source: paramsValue.value?.source || tabsOptions.value[0].key, source: paramsValue.value?.source || tabsOptions.value[0].key,

View File

@ -152,6 +152,7 @@ const paramsValue = reactive<TermsType>({
const showDelete = ref(false) const showDelete = ref(false)
const columnOptions: any = inject(ContextKey) // const columnOptions: any = inject(ContextKey) //
const columnType = ref<string>()
const termTypeOptions = ref<Array<{ id: string, name: string}>>([]) // const termTypeOptions = ref<Array<{ id: string, name: string}>>([]) //
const valueOptions = ref<any[]>([]) // const valueOptions = ref<any[]>([]) //
const metricOption = ref<any[]>([]) // termType const metricOption = ref<any[]>([]) // termType
@ -165,7 +166,7 @@ const handOptionByColumn = (option: any) => {
metricsCacheOption.value = option.metrics?.map((item: any) => ({...item, label: item.name})) || [] metricsCacheOption.value = option.metrics?.map((item: any) => ({...item, label: item.name})) || []
tabsOptions.value.length = 1 tabsOptions.value.length = 1
tabsOptions.value[0].component = option.dataType tabsOptions.value[0].component = option.dataType
columnType.value = option.dataType
if (option.metrics && option.metrics.length) { if (option.metrics && option.metrics.length) {
tabsOptions.value.push( tabsOptions.value.push(
@ -281,6 +282,7 @@ const termsTypeSelect = (e: { key: string, name: string }) => {
const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value
let value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue let value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
// timeTypeKeys // timeTypeKeys
if (columnType.value === 'date') {
if (timeTypeKeys.includes(e.key)) { if (timeTypeKeys.includes(e.key)) {
if (tabsOptions.value[0].component !== 'int') { if (tabsOptions.value[0].component !== 'int') {
value = undefined value = undefined
@ -290,6 +292,7 @@ const termsTypeSelect = (e: { key: string, name: string }) => {
value = undefined value = undefined
tabsOptions.value[0].component = 'date' tabsOptions.value[0].component = 'date'
} }
}
paramsValue.value = { paramsValue.value = {
source: paramsValue.value?.source || tabsOptions.value[0].key, source: paramsValue.value?.source || tabsOptions.value[0].key,

View File

@ -123,7 +123,6 @@ export const EventEmitter = {
} }
export const isActionChange = (_metadata: any, _message: any) => { export const isActionChange = (_metadata: any, _message: any) => {
console.log(_metadata, _message)
const _properties = _metadata?.properties || []; const _properties = _metadata?.properties || [];
const _functions = _metadata?.functions || []; const _functions = _metadata?.functions || [];
if ( if (

View File

@ -68,7 +68,7 @@
]" ]"
> >
<j-input <j-input
:disabled="record.scale !== undefined" :disabled="record.old_id"
v-model:value="record.name" v-model:value="record.name"
placeholder="请输入名称" placeholder="请输入名称"
/> />
@ -104,12 +104,10 @@
/> />
</j-form-item> </j-form-item>
</template> </template>
<template v-else-if="column.key === 'precision'"> <template v-else-if="column.key === 'scale'">
<j-form-item <j-form-item :name="['data', index, 'scale']">
:name="['data', index, 'precision']"
>
<j-input-number <j-input-number
v-model:value="record.precision" v-model:value="record.scale"
:min="0" :min="0"
:max="99999" :max="99999"
style="width: 100%" style="width: 100%"
@ -117,7 +115,15 @@
</j-form-item> </j-form-item>
</template> </template>
<template v-else-if="column.key === 'notnull'"> <template v-else-if="column.key === 'notnull'">
<j-form-item :name="['data', index, 'notnull']"> <j-form-item
:name="['data', index, 'notnull']"
:rules="[
{
required: true,
message: '请选择是否不能为空',
},
]"
>
<j-radio-group <j-radio-group
v-model:value="record.notnull" v-model:value="record.notnull"
button-style="solid" button-style="solid"
@ -132,7 +138,7 @@
</j-form-item> </j-form-item>
</template> </template>
<template v-else-if="column.key === 'comment'"> <template v-else-if="column.key === 'comment'">
<j-form-item :name="['data', index, 'notnull']"> <j-form-item :name="['data', index, 'comment']">
<j-input <j-input
v-model:value="record.comment" v-model:value="record.comment"
placeholder="请输入说明" placeholder="请输入说明"
@ -147,7 +153,8 @@
:danger="true" :danger="true"
:popConfirm="{ :popConfirm="{
title: `确认删除`, title: `确认删除`,
onConfirm: () => clickDel(record, index), onConfirm: () =>
clickDel(record, index),
}" }"
:disabled="record.status" :disabled="record.status"
> >
@ -217,6 +224,7 @@ import {
delSaveRow_api, delSaveRow_api,
} from '@/api/system/dataSource'; } from '@/api/system/dataSource';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { randomString } from '@/utils/utils';
import { FormInstance, message } from 'ant-design-vue'; import { FormInstance, message } from 'ant-design-vue';
import { DataNode } from 'ant-design-vue/lib/tree'; import { DataNode } from 'ant-design-vue/lib/tree';
import _ from 'lodash'; import _ from 'lodash';
@ -243,13 +251,14 @@ const columns = [
}, },
{ {
title: '精度', title: '精度',
dataIndex: 'precision', dataIndex: 'scale',
key: 'precision', key: 'scale',
}, },
{ {
title: '不能为空', title: '不能为空',
dataIndex: 'notnull', dataIndex: 'notnull',
key: 'notnull', key: 'notnull',
width: 130
}, },
{ {
title: '说明', title: '说明',
@ -287,6 +296,7 @@ const queryTables = (key: string) => {
rdbTables_api(id, key).then((resp: any) => { rdbTables_api(id, key).then((resp: any) => {
table.data = resp.result.columns.map( table.data = resp.result.columns.map(
(item: object, index: number) => ({ (item: object, index: number) => ({
old_id: randomString(),
...item, ...item,
index, index,
}), }),
@ -348,7 +358,7 @@ const table = reactive({
const addRow = () => { const addRow = () => {
const initData: dbColumnType = { const initData: dbColumnType = {
precision: 0, scale: 0,
length: 0, length: 0,
notnull: false, notnull: false,
type: '', type: '',
@ -363,19 +373,22 @@ const clickDel = (row: any, index: number) => {
delSaveRow_api(id, leftData.selectedKeys[0], [row.name]).then( delSaveRow_api(id, leftData.selectedKeys[0], [row.name]).then(
(resp: any) => { (resp: any) => {
if (resp.status === 200) { if (resp.status === 200) {
table.data.splice(index, 1) table.data.splice(index, 1);
} }
}, },
); );
} else { } else {
table.data.splice(index, 1) table.data.splice(index, 1);
}; }
}; };
const clickSave = () => { const clickSave = () => {
formRef.value.validate().then((_data: any) => { formRef.value.validate().then((_data: any) => {
const columns = cloneDeep(table.data); const columns = cloneDeep(table.data);
columns.forEach((item) => delete item.index); columns.forEach((item: any) => {
delete item?.old_id
delete item?.index
});
if (!columns.length) { if (!columns.length) {
onlyMessage('请配置数据源字段', 'error'); onlyMessage('请配置数据源字段', 'error');
return; return;

View File

@ -29,7 +29,7 @@ export type dbColumnType = {
previousName?: string, previousName?: string,
type: String, type: String,
length: number, length: number,
precision: number, scale: number,
notnull: boolean, notnull: boolean,
comment: string, comment: string,
name: string, name: string,

View File

@ -172,12 +172,16 @@ const confirm = () => {
return message.warning('请先勾选数据'); return message.warning('请先勾选数据');
} }
console.log('table.selectedRows: ', table.selectedRows);
const params = table.selectedRows.map((item: any) => ({ const params = table.selectedRows.map((item: any) => ({
targetType: 'org', targetType: 'org',
targetId: props.parentId, targetId: props.parentId,
assetType: props.assetType, assetType: props.assetType,
assetIdList: [item.id], assetIdList: [item.id],
permission: item.selectPermissions, // ,
permission: item.selectPermissions.filter((f: any) =>
item.permissionList.map((m: any) => m.value).includes(f),
),
})); }));
// , , // , ,

View File

@ -258,7 +258,6 @@
<script setup lang="ts"> <script setup lang="ts">
import PermissionButton from '@/components/PermissionButton/index.vue'; import PermissionButton from '@/components/PermissionButton/index.vue';
import { FormInstance, message } from 'ant-design-vue'; import { FormInstance, message } from 'ant-design-vue';
import ChooseIconDialog from '../components/ChooseIconDialog.vue'; import ChooseIconDialog from '../components/ChooseIconDialog.vue';
import PermissChoose from '../components/PermissChoose.vue'; import PermissChoose from '../components/PermissChoose.vue';

View File

@ -63,26 +63,29 @@
<script setup lang="ts"> <script setup lang="ts">
import PermissionButton from '@/components/PermissionButton/index.vue'; import PermissionButton from '@/components/PermissionButton/index.vue';
import ButtonAddDialog from '../components/ButtonAddDialog.vue'; import ButtonAddDialog from '../components/ButtonAddDialog.vue';
import { getMenuInfo_api, saveMenuInfo_api } from '@/api/system/menu'; import { getMenuInfo_api, saveMenuInfo_api } from '@/api/system/menu';
import { message } from 'jetlinks-ui-components'; import { message } from 'jetlinks-ui-components';
const permission = 'system/Menu'; const permission = 'system/Menu';
// //
const route = useRoute(); const route = useRoute();
const routeParams = { const routeParams = reactive({
id: route.params.id === ':id' ? '' : (route.params.id as string), id: route.params.id === ':id' ? '' : (route.params.id as string),
...route.query, ...route.query,
}; });
const paramsId = ref('');
// //
const selectItem = ref<any>({}); const selectItem = ref<any>({});
const dialogVisible = ref(false); const dialogVisible = ref(false);
const dialogTitle = ref<'查看' | '新增' | '编辑'>('新增'); const dialogTitle = ref<'查看' | '新增' | '编辑'>('新增');
const openDialog = (mode: '查看' | '新增' | '编辑', row: object) => { const openDialog = (mode: '查看' | '新增' | '编辑', row: object) => {
if (!routeParams.id) return message.warning('请先新增菜单基本信息'); if (!routeParams.id && !paramsId.value) {
return message.warning('请先新增菜单基本信息');
}
console.log(3);
selectItem.value = { ...row }; selectItem.value = { ...row };
dialogTitle.value = mode; dialogTitle.value = mode;
dialogVisible.value = true; dialogVisible.value = true;
@ -147,6 +150,15 @@ type tableDataItem = {
description?: string; description?: string;
permissions: object[]; permissions: object[];
}; };
watch(
() => route.params.id,
(value) => {
if (!!value) {
paramsId.value = value;
}
},
);
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -73,6 +73,7 @@ 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';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { MESSAGE_SUBSCRIBE_MENU_CODE, USER_CENTER_MENU_CODE } from '@/utils/consts'
const selectedKeys: any = ref([]); const selectedKeys: any = ref([]);
const treeData = ref<any>([]); const treeData = ref<any>([]);
@ -103,10 +104,55 @@ const params = {
], ],
}; };
// children
const filterAndClean = (data: any) => {
// data
if (Array.isArray(data)) {
return data
.filter((item) => item !== null) // null
.map((item: any) => filterAndClean(item)); //
}
// data
if (typeof data === 'object') {
let cleanedChildren = filterAndClean(data.children); //
if (Array.isArray(cleanedChildren)) {
cleanedChildren = cleanedChildren.filter((i) => i);
}
if (cleanedChildren !== undefined) {
data.children = cleanedChildren;
} else {
delete data.children; // children undefined
}
}
return data;
};
const handleOk = async () => { const handleOk = async () => {
const { arrMap, rootSet } = developArrToMap(
cloneDeep(treeData.value),
false,
true,
);
const dataMap = new Map();
// map
selectedKeys.value.forEach((item: string) => {
if (arrMap.has(item)) {
dataMap.set(item, arrMap.get(item));
}
});
const _saveDataMap = {
arrMap: dataMap,
rootSet,
};
const dataArr = filterAndClean(mergeMapToArr(_saveDataMap, _saveDataMap));
loading.value = true; loading.value = true;
const res = await updateMenus(treeData.value); const res = await updateMenus(dataArr).catch(() => {});
if (res.status === 200) { if (res?.status === 200) {
onlyMessage('操作成功', 'success'); onlyMessage('操作成功', 'success');
} }
loading.value = false; loading.value = false;
@ -140,7 +186,7 @@ onMounted(() => {
); );
getMenuTree_api(params).then((resp: any) => { getMenuTree_api(params).then((resp: any) => {
if (resp.status == 200) { if (resp.status == 200) {
systemMenu.value = resp.result; systemMenu.value = resp.result?.filter((item: { code: string }) => ![USER_CENTER_MENU_CODE, MESSAGE_SUBSCRIBE_MENU_CODE].includes(item.code));
// //
const baseMenuData = developArrToMap(baseMenu.value); const baseMenuData = developArrToMap(baseMenu.value);
const systemMenuData = developArrToMap(systemMenu.value, true); const systemMenuData = developArrToMap(systemMenu.value, true);

View File

@ -31,12 +31,12 @@ export const filterMenu = (permissions: string[], menus: any[]) => {
export const mergeMapToArr = (baseMenuData: any, systemMenuData: any) => { export const mergeMapToArr = (baseMenuData: any, systemMenuData: any) => {
const updataArr = (r: any) => { const updataArr = (r: any) => {
for (let i = 0; i < r.length; i++) { for (let i = 0; i < r.length; i++) {
const child = r[i].children; let child = r[i].children;
if (child) { if (child) {
updataArr(child); updataArr(child);
} }
r[i] = newMap.get(r[i].code); r[i] = newMap.get(r[i].code);
delete r[i].parentCode; r[i]?.parentCode && delete r[i].parentCode;
} }
}; };
const root: any = []; const root: any = [];
@ -45,7 +45,7 @@ export const mergeMapToArr = (baseMenuData: any, systemMenuData: any) => {
...new Set([...baseMenuData?.rootSet, ...systemMenuData.rootSet]), ...new Set([...baseMenuData?.rootSet, ...systemMenuData.rootSet]),
]; ];
newRootArr.forEach((item: any) => { newRootArr.forEach((item: any) => {
root.push(newMap.get(item)); newMap.has(item) && root.push(newMap.get(item));
}); });
updataArr(root); updataArr(root);
return root; return root;
@ -55,9 +55,10 @@ export const mergeMapToArr = (baseMenuData: any, systemMenuData: any) => {
* *
* @param value baseMenu systemMenu * @param value baseMenu systemMenu
* @param checked true * @param checked true
* @param save true
* @returns Mapkeys * @returns Mapkeys
*/ */
export const developArrToMap = (Menu: any, checked = false) => { export const developArrToMap = (Menu: any, checked = false, save = false) => {
const rootSet = new Set(); const rootSet = new Set();
const arrMap = new Map(); const arrMap = new Map();
const checkedKeys: any = []; const checkedKeys: any = [];
@ -65,10 +66,16 @@ export const developArrToMap = (Menu: any, checked = false) => {
arr.forEach((item: any) => { arr.forEach((item: any) => {
item.title = item.code; item.title = item.code;
item.key = item.code; item.key = item.code;
if (save) {
delete item.checked; //保存时删除 checked 字段
checkedKeys.push(item.code);
} else {
if (checked || item?.checked) { if (checked || item?.checked) {
item.checked = item?.checked || checked; item.checked = item?.checked || checked;
checkedKeys.push(item.code); checkedKeys.push(item.code);
} }
}
arrMap.set(item.code, item); arrMap.set(item.code, item);
if (parentCode === 'root') { if (parentCode === 'root') {
rootSet.add(item.code); //处理根菜单 rootSet.add(item.code); //处理根菜单

View File

@ -10,6 +10,7 @@
<j-radio-button <j-radio-button
v-for="typeStr in iconKeys" v-for="typeStr in iconKeys"
:value="typeStr" :value="typeStr"
:key="typeStr"
:class="{ active: selected === typeStr }" :class="{ active: selected === typeStr }"
> >
<AIcon :type="typeStr" /> <AIcon :type="typeStr" />
@ -19,6 +20,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import iconKeys from './fields';
const emits = defineEmits(['confirm', 'update:visible']); const emits = defineEmits(['confirm', 'update:visible']);
const props = defineProps<{ const props = defineProps<{
visible: boolean; visible: boolean;
@ -28,38 +30,6 @@ const confirm = () => {
emits('confirm', selected.value); emits('confirm', selected.value);
emits('update:visible', false); emits('update:visible', false);
}; };
const iconKeys = [
'EyeOutlined',
'EditOutlined',
'PlusOutlined',
'DeleteOutlined',
'CheckCircleOutlined',
'StopOutlined',
'CheckOutlined',
'CloseOutlined',
'DownOutlined',
'ImportOutlined',
'ExportOutlined',
'SyncOutlined',
'ExclamationCircleOutlined',
'UploadOutlined',
'LoadingOutlined',
'PlusCircleOutlined',
'QuestionCircleOutlined',
'DisconnectOutlined',
'LinkOutlined',
'PoweroffOutlined',
'SwapOutlined',
'BugOutlined',
'BarsOutlined',
'ArrowDownOutlined',
'SmallDashOutlined',
'TeamOutlined',
'MenuUnfoldOutlined',
'MenuFoldOutlined',
'InfoCircleOutlined',
'SearchOutlined',
];
const selected = ref<string>(''); const selected = ref<string>('');
</script> </script>

View File

@ -0,0 +1,246 @@
const direction = [
'StepBackward',
'StepForward',
'FastBackward',
'FastForward',
'Shrink',
'ArrowsAlt',
'Down',
'Up',
'Left',
'Right',
'CaretUp',
'CaretDown',
'CaretLeft',
'CaretRight',
'UpCircle',
'DownCircle',
'LeftCircle',
'RightCircle',
'DoubleRight',
'DoubleLeft',
'VerticalLeft',
'VerticalRight',
'VerticalAlignTop',
'VerticalAlignMiddle',
'VerticalAlignBottom',
'Forward',
'Backward',
'Rollback',
'Enter',
'Retweet',
'Swap',
'SwapLeft',
'SwapRight',
'ArrowUp',
'ArrowDown',
'ArrowLeft',
'ArrowRight',
'PlayCircle',
'UpSquare',
'DownSquare',
'LeftSquare',
'RightSquare',
'Login',
'Logout',
'MenuFold',
'MenuUnfold',
'BorderBottom',
'BorderHorizontal',
'BorderInner',
'BorderOuter',
'BorderLeft',
'BorderRight',
'BorderTop',
'BorderVerticle',
'PicCenter',
'PicLeft',
'PicRight',
'RadiusBottomleft',
'RadiusBottomright',
'RadiusUpleft',
'RadiusUpright',
'Fullscreen',
'FullscreenExit',
];
const suggestion = [
'Question',
'QuestionCircle',
'Plus',
'PlusCircle',
'Pause',
'PauseCircle',
'Minus',
'MinusCircle',
'PlusSquare',
'MinusSquare',
'Info',
'InfoCircle',
'Exclamation',
'ExclamationCircle',
'Close',
'CloseCircle',
'CloseSquare',
'Check',
'CheckCircle',
'CheckSquare',
'ClockCircle',
'Warning',
'IssuesClose',
'Stop',
];
const editor = [
'Edit',
'Form',
'Copy',
'Scissor',
'Delete',
'Snippets',
'Diff',
'Highlight',
'AlignCenter',
'AlignLeft',
'AlignRight',
'BgColors',
'Bold',
'Italic',
'Underline',
'Strikethrough',
'Redo',
'Undo',
'ZoomIn',
'ZoomOut',
'FontColors',
'FontSize',
'LineHeight',
'Dash',
'SmallDash',
'SortAscending',
'SortDescending',
'Drag',
'OrderedList',
'UnorderedList',
'RadiusSetting',
'ColumnWidth',
'ColumnHeight',
];
const data = [
'AreaChart',
'PieChart',
'BarChart',
'DotChart',
'LineChart',
'RadarChart',
'HeatMap',
'Fall',
'Rise',
'Stock',
'BoxPlot',
'Fund',
'Sliders',
];
// const logo = [
// 'Android',
// 'Apple',
// 'Windows',
// 'Ie',
// 'Chrome',
// 'Github',
// 'Aliwangwang',
// 'Dingding',
// 'WeiboSquare',
// 'WeiboCircle',
// 'TaobaoCircle',
// 'Html5',
// 'Weibo',
// 'Twitter',
// 'Wechat',
// 'Youtube',
// 'AlipayCircle',
// 'Taobao',
// 'Skype',
// 'Qq',
// 'MediumWorkmark',
// 'Gitlab',
// 'Medium',
// 'Linkedin',
// 'GooglePlus',
// 'Dropbox',
// 'Facebook',
// 'Codepen',
// 'CodeSandbox',
// 'CodeSandboxCircle',
// 'Amazon',
// 'Google',
// 'CodepenCircle',
// 'Alipay',
// 'AntDesign',
// 'AntCloud',
// 'Aliyun',
// 'Zhihu',
// 'Slack',
// 'SlackSquare',
// 'Behance',
// 'BehanceSquare',
// 'Dribbble',
// 'DribbbleSquare',
// 'Instagram',
// 'Yuque',
// 'Alibaba',
// 'Yahoo',
// 'Reddit',
// 'Sketch',
// ];
// 不显示,需要过滤
// const filter = [
// 'AlipaySquare',
// 'AmazonCircle',
// 'AmazonSquare',
// 'BehanceCircle',
// 'CodeSandboxSquare',
// 'CodeSandboxSquare',
// 'CodepenSquare',
// 'DingtalkCircle',
// 'DingtalkSquare',
// 'DribbbleCircle',
// 'DropboxCircle',
// 'DropboxSquare',
// 'Golden',
// 'GoogleCircle',
// 'GoogleSquare',
// 'GooglePlusCircle',
// 'GooglePlusSquare',
// 'GooglePlusSquare',
// 'IeCircle',
// 'IeSquare',
// 'MediumCircle',
// 'MediumSquare',
// 'QqCircle',
// 'QqSquare',
// 'RedditCircle',
// 'RedditSquare',
// 'Signal',
// 'SketchCircle',
// 'SketchSquare',
// 'SlackCircle',
// 'TaobaoSquare',
// 'TwitterCircle',
// 'TwitterSquare',
// 'ZhihuCircle',
// 'ZhihuSquare',
// 'createFromIconfontCN',
// 'default',
// 'getTwoToneColor',
// 'setTwoToneColor',
// ];
const datum = [...direction, ...suggestion, ...editor, ...data];
const iconKeys = datum.map((item) => item + 'Outlined');
export default iconKeys;

View File

@ -25,6 +25,7 @@
<AIcon type="PlusOutlined" />新增 <AIcon type="PlusOutlined" />新增
</PermissionButton> </PermissionButton>
<j-button <j-button
v-if="admin"
style="margin-left: 12px" style="margin-left: 12px"
@click="router.push('/system/Menu/Setting')" @click="router.push('/system/Menu/Setting')"
>菜单配置</j-button >菜单配置</j-button
@ -79,10 +80,12 @@
<script setup lang="ts" name="Menu"> <script setup lang="ts" name="Menu">
import PermissionButton from '@/components/PermissionButton/index.vue'; import PermissionButton from '@/components/PermissionButton/index.vue';
import { getMenuTree_api, delMenuInfo_api } from '@/api/system/menu'; import { getMenuTree_api, delMenuInfo_api } from '@/api/system/menu';
import { message } from 'jetlinks-ui-components'; import { message } from 'jetlinks-ui-components';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useUserInfo } from '@/store/userInfo';
import { MESSAGE_SUBSCRIBE_MENU_CODE, USER_CENTER_MENU_CODE } from '@/utils/consts'
const admin = useUserInfo().userInfos?.type.id === 'admin';
const permission = 'system/Menu'; const permission = 'system/Menu';
@ -108,7 +111,7 @@ const columns = [
search: { search: {
type: 'string', type: 'string',
}, },
width: 220, // width: 220,
}, },
{ {
title: '页面地址', title: '页面地址',
@ -133,7 +136,8 @@ const columns = [
title: '说明', title: '说明',
dataIndex: 'describe', dataIndex: 'describe',
key: 'describe', key: 'describe',
width: 200, ellipsis: true,
// width: 200,
}, },
{ {
title: '创建时间', title: '创建时间',
@ -150,8 +154,9 @@ const columns = [
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
key: 'action', key: 'action',
fixed: 'right',
scopedSlots: true, scopedSlots: true,
width: 140, width: 200,
}, },
]; ];
const queryParams = ref({ terms: [] }); const queryParams = ref({ terms: [] });
@ -201,7 +206,7 @@ const table = reactive({
return { return {
code: resp.message, code: resp.message,
result: { result: {
data: resp.result, data: resp.result?.filter((item: { code: string }) => ![USER_CENTER_MENU_CODE, MESSAGE_SUBSCRIBE_MENU_CODE].includes(item.code)),
pageIndex: resp.pageIndex, pageIndex: resp.pageIndex,
pageSize: resp.pageSize, pageSize: resp.pageSize,
total: resp.total, total: resp.total,
@ -246,6 +251,7 @@ const table = reactive({
<style lang="less" scoped> <style lang="less" scoped>
.menu-container { .menu-container {
width: 100%;
:deep(.ant-table-cell) { :deep(.ant-table-cell) {
.ant-btn-link { .ant-btn-link {
padding: 0; padding: 0;

View File

@ -51,6 +51,7 @@
import { FormInstance, message } from 'ant-design-vue'; import { FormInstance, message } from 'ant-design-vue';
import PermissTree from '../components/PermissTree.vue'; import PermissTree from '../components/PermissTree.vue';
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
import { USER_CENTER_MENU_DATA } from '@/views/init-home/data/baseMenu'
import { import {
getRoleDetails_api, getRoleDetails_api,
@ -71,7 +72,7 @@ const form = reactive({
name: '', name: '',
description: '', description: '',
}, },
menus: [], menus: [USER_CENTER_MENU_DATA],
getForm: () => { getForm: () => {
getRoleDetails_api(roleId).then((resp) => { getRoleDetails_api(roleId).then((resp) => {
if (resp.status) { if (resp.status) {

View File

@ -52,6 +52,7 @@
<j-checkbox <j-checkbox
v-model:checked="record.granted" v-model:checked="record.granted"
:indeterminate="record.indeterminate" :indeterminate="record.indeterminate"
:disabled='record.code === USER_CENTER_MENU_CODE'
@change="menuChange(record, true)" @change="menuChange(record, true)"
>{{ record.name }}</j-checkbox >{{ record.name }}</j-checkbox
> >
@ -63,6 +64,7 @@
v-for="button in record.buttons" v-for="button in record.buttons"
v-model:checked="button.granted" v-model:checked="button.granted"
@change="actionChange(record)" @change="actionChange(record)"
:disabled='[USER_CENTER_MENU_BUTTON_CODE].includes(button.id)'
>{{ button.name }}</j-checkbox >{{ button.name }}</j-checkbox
> >
</div> </div>
@ -98,9 +100,16 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { cloneDeep } from 'lodash-es'; import { cloneDeep, uniqBy } from 'lodash-es';
import { getPrimissTree_api } from '@/api/system/role'; import { getPrimissTree_api } from '@/api/system/role';
import { getCurrentInstance } from 'vue'; import { getCurrentInstance } from 'vue';
import {
USER_CENTER_MENU_BUTTON_CODE,
MESSAGE_SUBSCRIBE_MENU_BUTTON_CODE,
USER_CENTER_MENU_CODE,
MESSAGE_SUBSCRIBE_MENU_CODE
} from '@/utils/consts'
const emits = defineEmits(['update:selectItems']); const emits = defineEmits(['update:selectItems']);
const route = useRoute(); const route = useRoute();
const props = defineProps({ const props = defineProps({
@ -156,7 +165,7 @@ const selectAllChange = () => {
}); });
} }
}); });
console.log('selectAllChange: ', flatTableData); // console.log('selectAllChange: ', flatTableData);
indeterminate.value = false; indeterminate.value = false;
emits( emits(
'update:selectItems', 'update:selectItems',
@ -165,24 +174,25 @@ const selectAllChange = () => {
}; };
// - // -
const bulkShow = ref<boolean>(false); const bulkShow = ref<boolean>(false);
const bulkOptions = [ const bulkOptions = ref();
{ // const bulkOptions = [
label: '全部数据', // {
value: 'ignore', // label: '',
}, // value: 'ignore',
{ // },
label: '所在组织及下级组织', // {
value: 'org-include-children', // label: '',
}, // value: 'org-include-children',
{ // },
label: '所在组织', // {
value: 'org', // label: '',
}, // value: 'org',
{ // },
label: '自己创建的', // {
value: 'creator', // label: '',
}, // value: 'creator',
]; // },
// ];
const bulkValue = ref<string>(''); const bulkValue = ref<string>('');
const bulkChange = () => { const bulkChange = () => {
if (!bulkValue) return; if (!bulkValue) return;
@ -198,7 +208,7 @@ const bulkChange = () => {
}); });
} }
}); });
console.log('bulkChange: ', flatTableData); // console.log('bulkChange: ', flatTableData);
emits( emits(
'update:selectItems', 'update:selectItems',
flatTableData.filter((item) => item.granted), flatTableData.filter((item) => item.granted),
@ -221,9 +231,10 @@ const init = () => {
() => { () => {
// //
const selected = cloneDeep(flatTableData).filter( const selected = cloneDeep(flatTableData).filter(
(item) => (item: any) =>
(item.granted && item.parentId) || (item.granted && item.parentId) ||
(item.indeterminate && item.buttons), (item.indeterminate && item.buttons) ||
item.code === USER_CENTER_MENU_CODE || item.code === MESSAGE_SUBSCRIBE_MENU_CODE, //
); );
selected.forEach((item) => { selected.forEach((item) => {
@ -259,9 +270,17 @@ init();
function getAllPermiss() { function getAllPermiss() {
const id = route.params.id as string; const id = route.params.id as string;
getPrimissTree_api(id).then((resp) => { getPrimissTree_api(id).then((resp) => {
tableData.value = resp.result; const _result = resp.result
//
tableData.value = _result.map((item: { code: string , buttons: any[], granted: boolean}) => {
if (item.code === USER_CENTER_MENU_CODE) {
item.granted = true
item.buttons = item.buttons.map( b => ({...b, granted: true, enabled: true}))
}
return item
});
treeToSimple(resp.result); // treeToSimple(tableData.value); //
const selectList = flatTableData.filter((item) => item.granted); // const selectList = flatTableData.filter((item) => item.granted); //
emits('update:selectItems', selectList); // emits('update:selectItems', selectList); //
@ -396,6 +415,16 @@ function treeToSimple(treeData: tableItemType[]) {
flatTableData.push(item); flatTableData.push(item);
item.children && treeToSimple(item.children); item.children && treeToSimple(item.children);
}); });
// console.log('flatTableData: ', flatTableData);
// , assetAccesses
let assets: any[] = [];
flatTableData?.forEach((item: any) => {
assets = [...assets, ...item.assetAccesses];
});
bulkOptions.value = uniqBy(assets, 'supportId')?.map((m: any) => ({
label: m.name,
value: m.supportId,
}));
} }
/** /**
* 设置子节点的状态 * 设置子节点的状态

View File

@ -92,8 +92,8 @@ export default defineConfig(({ mode}) => {
[env.VITE_APP_BASE_API]: { [env.VITE_APP_BASE_API]: {
// target: 'http://192.168.33.22:8800', // target: 'http://192.168.33.22:8800',
// target: 'http://192.168.32.244:8881', // target: 'http://192.168.32.244:8881',
// target: 'http://120.77.179.54:8844', // 120测试 target: 'http://120.77.179.54:8844', // 120测试
target: 'http://192.168.33.46:8844', // 本地开发环境 // target: 'http://192.168.33.46:8844', // 本地开发环境
ws: 'ws://192.168.33.46:8844', ws: 'ws://192.168.33.46:8844',
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '') rewrite: (path) => path.replace(/^\/api/, '')

View File

@ -3700,8 +3700,8 @@ jetlinks-store@^0.0.3:
jetlinks-ui-components@^1.0.5: jetlinks-ui-components@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#c71ecae61776bff738f43efe46aac7264f092736" resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#8cbd59900e692dd931d289f3d5a6f4541485fd9f"
integrity sha512-+1a/4nA5RCiInRFyyaVCMEWSBzNU8lzxOYTTpY0GiNhuJuhGE5AbBsVp9CXXF0lFECK2iqaAElY+QN4Wjms1Dw== integrity sha512-ytX39qMt3kkEisURoIKlv2rAhGSvI74/WLLqkP6dJdz4q1k3UpANDtcnrz9rGRwTAKszVQ6kCga6VL6kGJiteQ==
dependencies: dependencies:
"@vueuse/core" "^9.12.0" "@vueuse/core" "^9.12.0"
ant-design-vue "^3.2.15" ant-design-vue "^3.2.15"