update: 优化vuex中的权限数据

This commit is contained in:
xieyonghong 2023-02-23 09:42:31 +08:00
parent 737a06e988
commit 0592de1e81
7 changed files with 431 additions and 24 deletions

View File

@ -0,0 +1,8 @@
import server from '@/utils/request';
export const modify = (id: string, data: any) => server.put(`/scene/${id}`, data)
export const save = (data: any) => server.post(`/scene`, data)
export const detail = (id: string) => server.get(`/scene/${id}`)

View File

@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
import { queryOwnThree } from '@/api/system/menu'
import { filterAsnycRouter, MenuItem } from '@/utils/menu'
import { isArray } from 'lodash-es'
import { usePermissionStore } from './permission'
import router from '@/router'
const defaultOwnParams = [
@ -45,26 +46,15 @@ export const useMenuStore = defineStore({
}),
getters: {
hasPermission(state) {
return (code: string | string[]) => {
if (!code) {
return (menuCode: string | string[]) => {
if (!menuCode) {
return true
}
if (!!Object.keys(state.menus).length) {
let codes: string[] = []
if (typeof code === 'string') {
codes.push(code)
} else {
codes = code
if (typeof menuCode === 'string') {
return !!this.menus[menuCode]
}
return codes.some(_c => {
const menu_code = _c.split(':')
if (menu_code.length > 1) {
return !!this.menus[menu_code[0]]?.buttons?.includes(menu_code[1])
}
return false
})
return menuCode.some(code => !!this.menus[code])
}
return false
}
@ -95,6 +85,8 @@ export const useMenuStore = defineStore({
//过滤非集成的菜单
const resp = await queryOwnThree({ paging: false, terms: defaultOwnParams })
if (resp.success) {
const permission = usePermissionStore()
permission.permissions = {}
const { menusData, silderMenus } = filterAsnycRouter(resp.result)
this.menus = {}
const handleMenuItem = (menu: any) => {
@ -104,6 +96,7 @@ export const useMenuStore = defineStore({
path: menuItem.path,
buttons: menuItem.meta.buttons
}
permission.permissions[menuItem.name] = menuItem.meta.buttons
if (menuItem.children && menuItem.children.length) {
handleMenuItem(menuItem.children)
}

132
src/store/scene.ts Normal file
View File

@ -0,0 +1,132 @@
import { defineStore } from 'pinia'
import type { BranchesType, FormModelType, SceneItem } from '@/views/rule-engine/Scene/typings'
import { detail } from '@/api/rule-engine/scene'
import { cloneDeep, isArray } from 'lodash-es'
import { randomString } from '@/utils/utils'
type DataType = {
data: FormModelType | any
productCache: any
}
const assignmentKey = (data: any[]): any[] => {
const onlyKey = ['when', 'then', 'terms', 'actions'];
if (!data) return [];
return data.map((item: any) => {
if (item) {
item.key = randomString();
Object.keys(item).some((key) => {
if (onlyKey.includes(key) && isArray(item[key])) {
item[key] = assignmentKey(item[key]);
}
});
}
return item;
});
};
export const defaultBranches = [
{
when: [
{
terms: [
{
column: undefined,
value: undefined,
termType: undefined,
key: 'params_1',
type: 'and',
},
],
type: 'and',
key: 'terms_1',
},
],
key: 'branches_1',
shakeLimit: {
enabled: false,
time: 1,
threshold: 1,
alarmFirst: false,
},
then: [],
},
];
const defaultOptions = {
trigger: {},
when: [
{
terms: [
{
terms: [],
},
],
},
],
};
export const useSceneStore = defineStore({
id: 'scene',
state: (): DataType => {
return {
data: {
trigger: { type: ''},
options: defaultOptions,
branches: defaultBranches,
description: ''
},
productCache: {}
}
},
actions: {
/**
*
*/
initData() {
},
/**
*
* @param id
*/
async getDetail(id: string) {
const resp = await detail(id)
if (resp.success) {
const result = resp.result as SceneItem
const triggerType = result.triggerType
let branches: any[] = result.branches
if (!branches) {
branches = cloneDeep(defaultBranches)
if (triggerType === 'device') {
branches.push(null)
}
} else {
const branchesLength = branches.length;
if (
triggerType === 'device' &&
((branchesLength === 1 && !!branches[0]?.when?.length) || // 有一组数据并且when有值
(branchesLength > 1 && !branches[branchesLength - 1]?.when?.length)) // 有多组否则数据并且最后一组when有值
) {
branches.push(null);
}
}
this.data = {
...result,
trigger: result.trigger || {},
branches: cloneDeep(assignmentKey(branches)),
options: {...defaultOptions, ...result.options },
}
}
},
getProduct() {
}
},
getters: {
}
})

View File

@ -0,0 +1,119 @@
<template>
<div :class='classNames'>
<div
v-for='item in options'
:key='item.value'
:class='["trigger-way-item", modelValue === item.value ? "active" : "" ]'
@click='handleClick(item.value)'
>
<div class='way-item-title'>
<p>{{ item.label }}</p>
<span>{{ item.tip}}</span>
</div>
<div class='way-item-image'>
<img width='40' :src='item.image' />
</div>
</div>
</div>
</template>
<script lang='ts' setup name='TriggerWay'>
import { getImage } from '@/utils/comm'
type Emit = {
(e: 'update:modelValue', data: string): void
}
const options = [
{ value: 'device', label: '设备触发', tip: '适用于设备数据或行为满足触发条件时,执行指定的动作', image: getImage('/device-trigger.png') },
{ value: 'manual', label: '手动触发', tip: '适用于第三方平台向物联网平台下发指令控制设备', image: getImage('/manual-trigger.png') },
{ value: 'timing', label: '定时触发', tip: '适用于定期执行固定任务', image: getImage('/timing-trigger.png') },
]
const props = defineProps({
modelValue: {
type: String,
default: ''
},
className: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
}
})
const emit = defineEmits<Emit>()
const classNames = computed(() => {
return {
[props.className]: true,
'scene-trigger-way-warp': true,
disabled: props.disabled
}
})
const handleClick = (type: string) => {
emit('update:modelValue', type)
}
</script>
<style scoped lang='less'>
@import 'ant-design-vue/es/style/themes/default.less';
.scene-trigger-way-warp {display: flex;
flex-wrap: wrap;
gap: 16px 24px;
width: 100%;
.trigger-way-item {
display: flex;
justify-content: space-between;
padding: 16px;
border: 1px solid #e0e4e8;
border-radius: 2px;
cursor: pointer;
transition: all 0.3s;
width: 204px;
.way-item-title {
p {
margin-bottom: 8px;
font-weight: bold;
font-size: 16px;
}
span {
color: rgba(#000, 0.35);
font-size: 12px;
}
}
.way-item-image {
display: flex;
align-items: center;
height: 100%;
margin: 0 !important;
opacity: 0.6;
}
&:hover {
color: @primary-color-hover;
.way-item-image {
opacity: 0.8;
}
}
&.active {
border-color: @primary-color-active;
.way-item-image {
opacity: 1;
}
}
}
}
</style>

View File

@ -1,13 +1,35 @@
<template>
<page-container>
<div class='scene-warp'>
<div></div>
<a-form ref='sceneForm' :model='data'>
</a-form>
<PermissionButton
type='primary'
hasPermission='rule-engine/Scene:update'
>
保存
</PermissionButton>
<!-- <a-button type='primary' :loading='loading'>保存</a-button>-->
</div>
</page-container>
</template>
<script>
export default {
name: 'index'
}
<script setup lang='ts' name='Scene'>
import { useSceneStore } from '@/store/scene'
const { getDetail, data } = useSceneStore()
const route = useRoute();
const loading = ref(false)
getDetail(route.query.id as string)
</script>
<style scoped>
<style scoped lang='less'>
.scene-warp {
padding: 24px;
background-color: #fff;
}
</style>

View File

@ -0,0 +1,104 @@
<template>
<a-modal
visible
:title='title'
:width='750'
:confirm-loading='loading'
:maskClosable='false'
@cancel='emit("close")'
@ok='handleOk'
>
<a-form
layout='vertical'
name='scene-save'
ref="formRef"
:model='formModel'
>
<a-form-item
name='name'
label='名称'
:rules="[
{ required: true, message: '请输入名称' },
{ max: 64, message: '最多输入64个字符' }
]"
>
<a-input v-model:value='formModel.name' placeholder='请输入名称' />
</a-form-item>
<a-form-item
:name='["trigger", "type"]'
label='触发方式'
:rules="[{ required: true, message: '请选择触发方式' }]"
>
<TriggerWay v-model:modelValue='formModel.trigger.type' :disabled='disabled' />
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup lang='ts'>
import { SceneItem } from '@/views/rule-engine/Scene/typings'
import TriggerWay from './components/TriggerWay.vue'
import type { PropType } from 'vue'
import type { FormInstance } from 'ant-design-vue';
import { save, modify } from '@/api/rule-engine/scene'
import { useMenuStore } from 'store/menu'
type Emit = {
(e: 'close'): void
}
const loading = ref(false)
const menuStory = useMenuStore()
const formModel = reactive({
name: '',
trigger: {
type: 'device'
}
})
const formRef = ref<FormInstance>()
const props = defineProps({
data: {
type: Object as PropType<Partial<SceneItem>>,
default: () => ({})
}
})
const emit = defineEmits<Emit>()
const title = computed(() => {
return props.data?.id ? '编辑' : '新增'
})
const disabled = computed(() => {
return !!props.data?.id
})
const handleOk = async () => {
if (formRef.value) {
const values = await formRef.value.validateFields()
let modelObj = { ...values }
if (props.data.id) {
modelObj = {
...props.data,
name: values.name
}
}
loading.value = true
const resp = props.data.id ? await modify(props.data.id, modelObj) : await save(modelObj)
loading.value = false
if (resp.success) {
emit('close')
const _id = props.data?.id || (resp.result as any).id
menuStory.jumpPage('rule-engine/Scene/Save', {}, { triggerType: values.trigger.type, id: _id })
}
}
}
</script>
<style scoped>
</style>

View File

@ -5,13 +5,24 @@
/>
<j-table
:columns='columns'
/>
>
<template #headerTitle>
<a-space>
<a-button type="primary" @click="visible = true">新增</a-button>
</a-space>
</template>
</j-table>
<SaveModal v-if='visible' @close='visible = false'/>
</page-container>
</template>
<script setup lang='ts'>
import SaveModal from './Save/save.vue'
import type { SceneItem } from './typings'
import { useMenuStore } from 'store/menu'
const menuStory = useMenuStore()
const visible = ref<boolean>(false)
const columns = [
{
@ -52,6 +63,24 @@ const columns = [
}
}
]
/**
* 编辑
* @param id
* @param triggerType 触发类型
*/
const handleEdit = (id: string, triggerType: string) => {
menuStory.jumpPage('Scene/Save', { }, { triggerType: triggerType, id, type: 'edit' })
}
/**
* 查看
* @param id
* @param triggerType 触发类型
*/
const handleView = (id: string, triggerType: string) => {
menuStory.jumpPage('Scene/Save', { }, { triggerType: triggerType, id, type: 'view' })
};
</script>
<style scoped>