|  | @@ -1,7 +1,6 @@
 | 
	
		
			
				|  |  |  <script setup lang="ts">
 | 
	
		
			
				|  |  |  import {ref} from "vue";
 | 
	
		
			
				|  |  | -import {isDev} from "@/utils/public";
 | 
	
		
			
				|  |  | -import {IntergrationMenu} from "@/api/settings/menu-settings";
 | 
	
		
			
				|  |  | +import {IntergrationMenu, updateMenuSettings} from "@/api/settings/menu-settings";
 | 
	
		
			
				|  |  |  import {
 | 
	
		
			
				|  |  |    ElButton,
 | 
	
		
			
				|  |  |    ElCascader,
 | 
	
	
		
			
				|  | @@ -13,21 +12,28 @@ import {
 | 
	
		
			
				|  |  |    ElInput,
 | 
	
		
			
				|  |  |    ElPopover,
 | 
	
		
			
				|  |  |    ElInputNumber,
 | 
	
		
			
				|  |  | -  ElSwitch
 | 
	
		
			
				|  |  | +  ElSwitch,
 | 
	
		
			
				|  |  | +  FormRules,
 | 
	
		
			
				|  |  | +  ElSelectV2
 | 
	
		
			
				|  |  |  } from "element-plus";
 | 
	
		
			
				|  |  |  import XEUtils from "xe-utils";
 | 
	
		
			
				|  |  |  import icon from '@/icons/iconfont.css'
 | 
	
		
			
				|  |  |  import {eachAndReturnList} from "@/utils/cyRefList";
 | 
	
		
			
				|  |  | +import {useCompRef} from "@/utils/useCompRef";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const props = defineProps<{
 | 
	
		
			
				|  |  | -  menuTreeData: any[],
 | 
	
		
			
				|  |  | +  cascaderData: any[],
 | 
	
		
			
				|  |  | +}>()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const emits = defineEmits<{
 | 
	
		
			
				|  |  | +  (e: "saveCallback"): void,
 | 
	
		
			
				|  |  |  }>()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  declare type VueIntergrationPlatformMenu = {
 | 
	
		
			
				|  |  | -  parentCascader: number[]
 | 
	
		
			
				|  |  | +  cascaders: number[]
 | 
	
		
			
				|  |  |  } & IntergrationMenu
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const showDialog = ref(isDev)
 | 
	
		
			
				|  |  | +const showDialog = ref(false)
 | 
	
		
			
				|  |  |  const currentData = ref<VueIntergrationPlatformMenu>({
 | 
	
		
			
				|  |  |    children: [],
 | 
	
		
			
				|  |  |    component: "",
 | 
	
	
		
			
				|  | @@ -37,7 +43,7 @@ const currentData = ref<VueIntergrationPlatformMenu>({
 | 
	
		
			
				|  |  |    metaPassRule: false,
 | 
	
		
			
				|  |  |    metaTitle: "",
 | 
	
		
			
				|  |  |    name: "",
 | 
	
		
			
				|  |  | -  parentCascader: [],
 | 
	
		
			
				|  |  | +  cascaders: [],
 | 
	
		
			
				|  |  |    parentId: 0,
 | 
	
		
			
				|  |  |    path: "",
 | 
	
		
			
				|  |  |    pathParams: "",
 | 
	
	
		
			
				|  | @@ -46,18 +52,65 @@ const currentData = ref<VueIntergrationPlatformMenu>({
 | 
	
		
			
				|  |  |    type: 0
 | 
	
		
			
				|  |  |  })
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -function save() {
 | 
	
		
			
				|  |  | -  if (currentData.value.parentCascader.length > 0) {
 | 
	
		
			
				|  |  | -    currentData.value.parentId = currentData.value.parentCascader[currentData.value.parentCascader.length - 1]
 | 
	
		
			
				|  |  | +const fromRef = useCompRef(ElForm)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const rules: FormRules<VueIntergrationPlatformMenu> = reactive({})
 | 
	
		
			
				|  |  | +type D = keyof VueIntergrationPlatformMenu
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function addRequired(key: D[]) {
 | 
	
		
			
				|  |  | +  key.forEach(item => {
 | 
	
		
			
				|  |  | +    rules[item] = [{required: true, trigger: 'change', message: '必填'}]
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +addRequired(['path', 'component', 'name', 'metaTitle'])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +async function save() {
 | 
	
		
			
				|  |  | +  await fromRef.value?.validate()
 | 
	
		
			
				|  |  | +  if (currentData.value.cascaders.length > 0) {
 | 
	
		
			
				|  |  | +    currentData.value.parentId = currentData.value.cascaders[currentData.value.cascaders.length - 1]
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  await updateMenuSettings(currentData.value)
 | 
	
		
			
				|  |  | +  emits('saveCallback')
 | 
	
		
			
				|  |  | +  showDialog.value = false
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +const icons = ref([])
 | 
	
		
			
				|  |  | +const routerKey = ref([])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const layout = [
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    value: 'Layout',
 | 
	
		
			
				|  |  | +    label: 'Layout'
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    value: 'EmptyRouter',
 | 
	
		
			
				|  |  | +    label: 'EmptyRouter'
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function dialogOpen() {
 | 
	
		
			
				|  |  | +  const regex = /.(?<icon>.*):before/g;
 | 
	
		
			
				|  |  | +  const matches = (icon as string).matchAll(regex);
 | 
	
		
			
				|  |  | +  icons.value = eachAndReturnList((matches as string[]), (item) => {
 | 
	
		
			
				|  |  | +    return item[1]
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const view = import.meta.glob('/src/views/**/*.{vue,tsx}');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  routerKey.value = eachAndReturnList(Object.keys(view), (item) => {
 | 
	
		
			
				|  |  | +    const tmp = item.replace("/src", "..")
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +      value: tmp,
 | 
	
		
			
				|  |  | +      label: tmp,
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  routerKey.value.push(...layout)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const regex = /.(?<icon>.*):before/g;
 | 
	
		
			
				|  |  | -const matches = (icon as string).matchAll(regex);
 | 
	
		
			
				|  |  | -const icons = ref(eachAndReturnList((matches as string[]), (item) => {
 | 
	
		
			
				|  |  | -  return item[1]
 | 
	
		
			
				|  |  | -}))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  function iconClick(icon) {
 | 
	
		
			
				|  |  |    currentData.value.icon = `iconfont ${icon}`
 | 
	
	
		
			
				|  | @@ -66,7 +119,6 @@ function iconClick(icon) {
 | 
	
		
			
				|  |  |  defineExpose({
 | 
	
		
			
				|  |  |    openDialog: (row: VueIntergrationPlatformMenu) => {
 | 
	
		
			
				|  |  |      currentData.value = XEUtils.clone(row, true)
 | 
	
		
			
				|  |  | -    currentData.value.parentCascader = []
 | 
	
		
			
				|  |  |      showDialog.value = true;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  })
 | 
	
	
		
			
				|  | @@ -75,43 +127,54 @@ defineExpose({
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  <template>
 | 
	
		
			
				|  |  |    <el-dialog v-model="showDialog"
 | 
	
		
			
				|  |  | +             @open="dialogOpen"
 | 
	
		
			
				|  |  |               title="菜单编辑"
 | 
	
		
			
				|  |  |               destroy-on-close
 | 
	
		
			
				|  |  |               draggable>
 | 
	
		
			
				|  |  | -    <el-form label-width="80px" size="default">
 | 
	
		
			
				|  |  | +    <el-form
 | 
	
		
			
				|  |  | +        ref="fromRef"
 | 
	
		
			
				|  |  | +        :model="currentData"
 | 
	
		
			
				|  |  | +        :rules="rules"
 | 
	
		
			
				|  |  | +        label-width="80px"
 | 
	
		
			
				|  |  | +        size="default">
 | 
	
		
			
				|  |  |        <el-row :gutter="10">
 | 
	
		
			
				|  |  |          <el-col :span="24">
 | 
	
		
			
				|  |  | -          <el-form-item label="父节点">
 | 
	
		
			
				|  |  | +          <el-form-item label="父节点" prop="cascaders">
 | 
	
		
			
				|  |  |              <el-cascader
 | 
	
		
			
				|  |  | -                v-model="currentData.parentCascader"
 | 
	
		
			
				|  |  | +                v-model="currentData.cascaders"
 | 
	
		
			
				|  |  |                  style="width: 100%"
 | 
	
		
			
				|  |  |                  :props="{ checkStrictly: true, value: 'id', label: 'metaTitle' }"
 | 
	
		
			
				|  |  | -                :options="menuTreeData"
 | 
	
		
			
				|  |  | +                :options="cascaderData"
 | 
	
		
			
				|  |  |                  clearable/>
 | 
	
		
			
				|  |  |            </el-form-item>
 | 
	
		
			
				|  |  |          </el-col>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          <el-col :span="24">
 | 
	
		
			
				|  |  | -          <el-form-item label="完整路径">
 | 
	
		
			
				|  |  | +          <el-form-item label="路径" prop="path">
 | 
	
		
			
				|  |  |              <el-input v-model="currentData.path"/>
 | 
	
		
			
				|  |  |            </el-form-item>
 | 
	
		
			
				|  |  |          </el-col>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          <el-col :span="24">
 | 
	
		
			
				|  |  | -          <el-form-item label="组件路径">
 | 
	
		
			
				|  |  | -            <el-input v-model="currentData.component"/>
 | 
	
		
			
				|  |  | +          <el-form-item label="组件路径" prop="component">
 | 
	
		
			
				|  |  | +            <el-select-v2
 | 
	
		
			
				|  |  | +                v-model="currentData.component"
 | 
	
		
			
				|  |  | +                :options="routerKey"
 | 
	
		
			
				|  |  | +                style="width: 100%"
 | 
	
		
			
				|  |  | +                filterable
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |            </el-form-item>
 | 
	
		
			
				|  |  |          </el-col>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          <el-col :span="24">
 | 
	
		
			
				|  |  | -          <el-form-item label="路径参数">
 | 
	
		
			
				|  |  | +          <el-form-item label="路径参数" prop="pathParams">
 | 
	
		
			
				|  |  |              <el-input v-model="currentData.pathParams"/>
 | 
	
		
			
				|  |  |            </el-form-item>
 | 
	
		
			
				|  |  |          </el-col>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          <el-col :span="12">
 | 
	
		
			
				|  |  | -          <el-form-item label="类型">
 | 
	
		
			
				|  |  | +          <el-form-item label="类型" prop="type">
 | 
	
		
			
				|  |  |              <el-switch v-model="currentData.type"
 | 
	
		
			
				|  |  |                         :active-value="1"
 | 
	
		
			
				|  |  |                         :inactive-value="2"
 | 
	
	
		
			
				|  | @@ -122,7 +185,7 @@ defineExpose({
 | 
	
		
			
				|  |  |          </el-col>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          <el-col :span="12">
 | 
	
		
			
				|  |  | -          <el-form-item label="路由名称">
 | 
	
		
			
				|  |  | +          <el-form-item label="路由名称" prop="name">
 | 
	
		
			
				|  |  |              <el-input v-model="currentData.name"
 | 
	
		
			
				|  |  |                        clearable maxlength="50"/>
 | 
	
		
			
				|  |  |            </el-form-item>
 | 
	
	
		
			
				|  | @@ -155,7 +218,7 @@ defineExpose({
 | 
	
		
			
				|  |  |          </el-col>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          <el-col :span="12">
 | 
	
		
			
				|  |  | -          <el-form-item label="菜单名称">
 | 
	
		
			
				|  |  | +          <el-form-item label="菜单名称" prop="metaTitle">
 | 
	
		
			
				|  |  |              <el-input v-model="currentData.metaTitle"
 | 
	
		
			
				|  |  |                        clearable maxlength="50"/>
 | 
	
		
			
				|  |  |            </el-form-item>
 | 
	
	
		
			
				|  | @@ -196,6 +259,38 @@ defineExpose({
 | 
	
		
			
				|  |  |            </el-form-item>
 | 
	
		
			
				|  |  |          </el-col>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        <el-col :span="12">
 | 
	
		
			
				|  |  | +          <el-form-item label="卡片类型">
 | 
	
		
			
				|  |  | +            <el-switch v-model="currentData.mainCard"
 | 
	
		
			
				|  |  | +                       :active-value="1"
 | 
	
		
			
				|  |  | +                       :inactive-value="0"
 | 
	
		
			
				|  |  | +                       active-text="是"
 | 
	
		
			
				|  |  | +                       inactive-text="否"
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </el-form-item>
 | 
	
		
			
				|  |  | +        </el-col>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <el-col :span="12">
 | 
	
		
			
				|  |  | +          <el-form-item label="超出滚动">
 | 
	
		
			
				|  |  | +            <el-switch v-model="currentData.mainOverflowAuto"
 | 
	
		
			
				|  |  | +                       :active-value="1"
 | 
	
		
			
				|  |  | +                       :inactive-value="0"
 | 
	
		
			
				|  |  | +                       active-text="是"
 | 
	
		
			
				|  |  | +                       inactive-text="否"
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </el-form-item>
 | 
	
		
			
				|  |  | +        </el-col>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <el-col :span="12">
 | 
	
		
			
				|  |  | +          <el-form-item label="无需登录">
 | 
	
		
			
				|  |  | +            <el-switch v-model="currentData.metaNeedToken"
 | 
	
		
			
				|  |  | +                       :active-value="1"
 | 
	
		
			
				|  |  | +                       :inactive-value="0"
 | 
	
		
			
				|  |  | +                       active-text="是"
 | 
	
		
			
				|  |  | +                       inactive-text="否"
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </el-form-item>
 | 
	
		
			
				|  |  | +        </el-col>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        </el-row>
 | 
	
		
			
				|  |  |      </el-form>
 |