diff --git a/src/api/permission/feature.js b/src/api/permission/feature.js index 1da6d93..21bca43 100644 --- a/src/api/permission/feature.js +++ b/src/api/permission/feature.js @@ -6,6 +6,19 @@ export const search = (params) => { params, }); }; +export const searchFree = () => { + return request({ + url: '/uc/permission/NotDistribution', + method: 'get', + }); +}; +export const assign = (params) => { + return request({ + url: '/uc/permission/menu', + method: 'put', + params, + }); +}; export const create = (data) => { return request({ url: '/uc/permission', diff --git a/src/components/extra/ElTable.vue b/src/components/extra/ElTable.vue index 9040e83..f9d2890 100644 --- a/src/components/extra/ElTable.vue +++ b/src/components/extra/ElTable.vue @@ -226,8 +226,21 @@ console.error('可拖拽表格ID不存在'); } }; - // 元素实例化后初始化sortablejs - onMounted(handleInit); + if (props.sortable) { + // 元素实例化后初始化sortablejs + onMounted(handleInit); + } else { + watch( + () => props.sortable, + (value, old) => { + if (!old && value) { + handleInit(); + } else if (old && !value) { + sortable.value.destroy(); + } + } + ); + } // 代理原生函数 const handleProxy = (fnName, args) => { return unref(refsTable)[fnName]?.apply(unref(refsTable), args); diff --git a/src/store/modules/operation/advertise/advertise.js b/src/store/modules/operation/advertise/advertise.js index 7b9294b..b90dc3f 100644 --- a/src/store/modules/operation/advertise/advertise.js +++ b/src/store/modules/operation/advertise/advertise.js @@ -165,6 +165,15 @@ const actions = { ElMessage.error((data.isEnable ? '启用' : '禁用') + '失败'); } }, + sort: async ({ dispatch }, data) => { + let res = await api.sort(data); + if (res) { + ElMessage.success('排序成功'); + dispatch('search'); + } else { + ElMessage.error('排序失败'); + } + }, }; export default { state, diff --git a/src/store/modules/permission/menu/feature.js b/src/store/modules/permission/menu/feature.js index 35829c8..8f7f286 100644 --- a/src/store/modules/permission/menu/feature.js +++ b/src/store/modules/permission/menu/feature.js @@ -7,6 +7,16 @@ const state = () => ({ total: 0, opts: { init: false, + type: [ + { + label: '需要分配', + value: 1, + }, + { + label: '登录即有', + value: 2, + }, + ], }, }); const getters = {}; @@ -38,6 +48,13 @@ const actions = { } return res; }, + assign: async (context, data) => { + let res = await api.assign(data); + if (!res) { + ElMessage.error('分配失败'); + } + return res; + }, save: async ({ dispatch }, data) => { if (!data.parentId) { data.parentId = 0; diff --git a/src/store/modules/permission/menu/menu.js b/src/store/modules/permission/menu/menu.js index fb9aa22..50d68e5 100644 --- a/src/store/modules/permission/menu/menu.js +++ b/src/store/modules/permission/menu/menu.js @@ -1,3 +1,4 @@ +import * as featureAPI from '@/api/permission/feature.js'; import * as api from '@/api/permission/menu.js'; import * as systemAPI from '@/api/permission/system.js'; import { ElMessage, ElMessageBox } from '@/plugins/element-plus'; @@ -9,6 +10,7 @@ const state = () => ({ opts: { init: false, system: [], + free: [], type: [ { label: '目录', @@ -64,6 +66,7 @@ const actions = { ...state.opts, init: true, system: await systemAPI.search(), + free: await featureAPI.searchFree(), }); }, detail: async (context, id) => { diff --git a/src/views/operation/advertise/index.vue b/src/views/operation/advertise/index.vue index e588dc4..a81bd03 100644 --- a/src/views/operation/advertise/index.vue +++ b/src/views/operation/advertise/index.vue @@ -7,22 +7,31 @@ :data="list" :operation="['create', 'search', 'remove']" :reset="handleReset" + :sortable="!!(state.condition.platform && state.condition.location)" title="广告" :total="total" @create="handleCreate" @remove="handleRemove" + @row-sort="handleSort" @search="handleSearch" > + + 选择广告平台和广告位置后可以对广告进行拖动排序 + - - + + - + - - + + @@ -87,6 +96,19 @@ loading.value = false; }; onActivated(handleSearch); + watch( + [() => state.condition.platform, () => state.condition.location], + (value) => { + if (value[0] && value[1]) { + if (value[0] === 2) { + state.condition.location = 1; + store.commit('advertise/setCondition', _.cloneDeep(state.condition)); + } + handleSearch(); + } + }, + { immediate: true, deep: true } + ); const handleCreate = () => { router.push({ name: 'CreateAdvertise' }); }; @@ -104,6 +126,17 @@ await store.dispatch('advertise/enable', row); loading.value = false; }; + const handleSort = async (newIndex, oldIndex) => { + loading.value = true; + await store.dispatch('advertise/sort', { + id: unref(list)[newIndex].id, + platform: state.condition.platform, + location: state.condition.location, + oldSort: unref(list)[newIndex].sort, + newSort: unref(list)[oldIndex].sort, + }); + loading.value = false; + }; const config = reactive({ // 表格列配置 columns: [ @@ -188,11 +221,4 @@ }); - + diff --git a/src/views/permission/menu/index.vue b/src/views/permission/menu/index.vue index d85365f..627051b 100644 --- a/src/views/permission/menu/index.vue +++ b/src/views/permission/menu/index.vue @@ -35,7 +35,7 @@ value: 'id', children: 'menuChild', }" - @current-change="(data) => (state.condition2.menuId = data.id)" + @node-click="(data) => handleCreateMenu(data)" > @@ -46,9 +46,6 @@ - - - @@ -58,12 +55,12 @@ - + 功能 - 新增 + 新增 @@ -78,6 +75,7 @@ label: 'name', value: 'id', }" + @node-click="(data) => handleCreateFeature(data)" > @@ -85,12 +83,9 @@ {{ data.name }} - - - - + @@ -137,10 +132,10 @@ - + - + @@ -201,23 +196,52 @@ /> - + + + + - + + + + 保存 + + + + + + + + 取消 + + 保存 + + + @@ -227,6 +251,7 @@ const store = useStore(); const { proxy } = getCurrentInstance(); const opts = computed(() => store.state.menu.opts); + const opts2 = computed(() => store.state.feature.opts); if (!unref(opts).init) { store.dispatch('menu/load'); } @@ -243,6 +268,15 @@ await store.dispatch('menu/search'); loading.value = false; }; + watch( + () => unref(opts).system, + (value) => { + state.condition.systemId = value?.[0]?.id; + }, + { + deep: true, + } + ); watch( () => state.condition, (value) => { @@ -297,7 +331,11 @@ }, }); const handleCreateMenu = (row, parent) => { + if (row) { + state.condition2.menuId = row.id; + } menuState.formVisible = true; + featureState.formVisible = false; Object.assign( menuState.form, row || { @@ -341,6 +379,7 @@ /* 功能表单 */ const refsFeatureForm = ref(null); + const refsPickForm = ref(null); const featureState = reactive({ formVisible: false, submitting: false, @@ -349,21 +388,66 @@ systemId: null, menuId: null, name: null, + service: null, method: 'GET', uri: null, + type: 1, isEnable: true, }, rules: { systemId: [{ required: true, message: '所属系统不能为空' }], menuId: [{ required: true, message: '所属菜单不能为空' }], name: [{ required: true, message: '功能名称不能为空' }], + service: [{ required: true, message: '服务名称不能为空' }], method: [{ required: true, message: '请求方式不能为空' }], uri: [{ required: true, message: '接口路径不能为空' }], + type: [{ required: true, message: '权限类型不能为空' }], isEnable: [{ required: true, message: '是否启用不能为空' }], }, + pickVisible: false, + pick: { + permissionId: null, + menuId: null, + }, + pickRules: { + permissionId: [{ required: true, message: '功能权限不能为空' }], + }, }); - const handleCreateFeature = (row) => { + const handleCancelPick = () => { + featureState.pickVisible = false; + featureState.pick = { + permissionId: null, + menuId: null, + }; + }; + const handleSavePick = async () => { + featureState.submitting = true; + try { + await proxy.$validate(refsPickForm); + let res = await store.dispatch('feature/assign', featureState.pick); + if (res) { + handleSearchFeature(); + handleCancelPick(); + store.dispatch('menu/load'); + } + } catch (e) { + console.info('取消保存', e); + } + featureState.submitting = false; + }; + const handlePickFeature = async () => { + try { + await proxy.$confirm('是否选择尚未分配菜单的功能权限?'); + featureState.formVisible = false; + featureState.pickVisible = true; + featureState.pick.menuId = state.condition2.menuId; + } catch (e) { + handleCreateFeature(); + } + }; + const handleCreateFeature = async (row) => { featureState.formVisible = true; + menuState.formVisible = false; Object.assign( featureState.form, row || { @@ -371,8 +455,10 @@ systemId: state.condition.systemId, menuId: state.condition2.menuId, name: null, + service: null, method: 'GET', uri: null, + type: 1, isEnable: true, } ); @@ -391,12 +477,12 @@ } featureState.submitting = false; }; - const handleDeleteFeature = (data) => { - store.dispatch( - 'feature/remove', - data.map((item) => item.id) - ); - }; + // const handleDeleteFeature = (data) => { + // store.dispatch( + // 'feature/remove', + // data.map((item) => item.id) + // ); + // };