|
@@ -1,47 +1,77 @@
|
|
|
<template>
|
|
|
<!-- 角色权限 - 添加角色 -->
|
|
|
- <div class="rolePage flex-col">
|
|
|
+ <div class="role-container">
|
|
|
<s-header :name="pageTitle" :noback="false"></s-header>
|
|
|
- <div class="accountPerBox flex-col">
|
|
|
+ <div class="permission-wrapper">
|
|
|
<van-form @submit="onSubmit">
|
|
|
- <van-field v-model="roleName" name="roleName" :label="$t('role.roleNameLabel')"
|
|
|
- :placeholder="$t('role.roleNamePlaceholder')"
|
|
|
- :rules="[{ required: true, message: $t('role.roleNamePlaceholder') }]" />
|
|
|
- <van-checkbox-group v-model="roleMenuCode" style="
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
- align-items: center;
|
|
|
- justify-content: flex-start;
|
|
|
- ">
|
|
|
- <van-checkbox v-for="(item, index) in menuCodeList" :key="index" :name="item.value"
|
|
|
- style="width: 160px; padding: 10px">{{ item.label }}</van-checkbox>
|
|
|
- </van-checkbox-group>
|
|
|
- <!-- 操作 -->
|
|
|
- <van-row justify="space-around" style="padding: 1em">
|
|
|
- <van-button span="5" round type="primary" style="height: 2em; padding: 0 2em" native-type="submit">
|
|
|
+ <!-- 角色名称输入 -->
|
|
|
+ <van-cell-group class="input-card">
|
|
|
+ <van-field v-model="roleName" name="roleName" :label="$t('role.roleNameLabel')"
|
|
|
+ :placeholder="$t('role.roleNamePlaceholder')"
|
|
|
+ :rules="[{ required: true, message: $t('role.roleNamePlaceholder') }]" clearable />
|
|
|
+ </van-cell-group>
|
|
|
+
|
|
|
+ <!-- 全局操作按钮 -->
|
|
|
+ <!-- <div class="bulk-actions">
|
|
|
+ <van-button size="small" @click="toggleAll(true)">全选</van-button>
|
|
|
+ <van-button size="small" @click="toggleAll(false)">反选</van-button>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!-- 权限分类 -->
|
|
|
+ <div class="permission-section">
|
|
|
+ <!-- 常用操作权限 -->
|
|
|
+ <div class="permission-card common-card">
|
|
|
+ <div class="card-header">
|
|
|
+ <div class="header-left">
|
|
|
+ <van-icon name="todo-list" class="card-icon" />
|
|
|
+ <h3 class="card-title">{{ $t('role.commonPermission') }}</h3>
|
|
|
+ </div>
|
|
|
+ <div class="header-actions">
|
|
|
+ <van-button size="mini" @click="toggleCategory('common', true)" class="action-btn">{{ $t('role.toggleAll') }}</van-button>
|
|
|
+ <van-button size="mini" @click="toggleCategory('common', false)" class="action-btn">{{ $t('role.toggleNoAll') }}</van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <van-checkbox-group v-model="roleMenuCode">
|
|
|
+ <div class="checkbox-grid">
|
|
|
+ <van-checkbox v-for="(item, index) in menuCodeList" :key="'common-' + index" :name="item"
|
|
|
+ shape="square" icon-size="18" class="perm-item">
|
|
|
+ <span class="perm-label">{{ $t("permission." + item) }}</span>
|
|
|
+ </van-checkbox>
|
|
|
+ </div>
|
|
|
+ </van-checkbox-group>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 远程操作权限 -->
|
|
|
+ <div class="permission-card remote-card" v-if="roleMenuCode.includes('M1')">
|
|
|
+ <div class="card-header">
|
|
|
+ <div class="header-left">
|
|
|
+ <van-icon name="setting" class="card-icon warn-icon" />
|
|
|
+ <h3 class="card-title">{{ $t('role.remotePermission') }}</h3>
|
|
|
+ </div>
|
|
|
+ <div class="header-actions">
|
|
|
+ <van-button size="mini" @click="toggleCategory('remote', true)" class="action-btn">{{ $t('role.toggleAll') }}</van-button>
|
|
|
+ <van-button size="mini" @click="toggleCategory('remote', false)" class="action-btn">{{ $t('role.toggleNoAll') }}</van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <van-checkbox-group v-model="controlCode">
|
|
|
+ <div class="checkbox-grid">
|
|
|
+ <van-checkbox v-for="(item, index) in remoteCodeList" :key="'remote-' + index" :name="item"
|
|
|
+ shape="square" icon-size="18" class="perm-item danger-item">
|
|
|
+ <span class="perm-label">{{ $t("remote." + item) }}</span>
|
|
|
+ </van-checkbox>
|
|
|
+ </div>
|
|
|
+ </van-checkbox-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 提交按钮 -->
|
|
|
+ <div class="submit-footer">
|
|
|
+ <van-button round block type="primary" native-type="submit" class="submit-btn">
|
|
|
{{ pageTitle }}
|
|
|
</van-button>
|
|
|
- </van-row>
|
|
|
+ </div>
|
|
|
</van-form>
|
|
|
</div>
|
|
|
- <!-- <van-popup v-model:show="roleShow" round position="bottom">
|
|
|
- <van-cascader
|
|
|
- v-model="roleList"
|
|
|
- :title="$t('role.pleaseSelectARole')"
|
|
|
- :options="roleOptions"
|
|
|
- @close="roleShow = false"
|
|
|
- @finish="onRoleFinish"
|
|
|
- />
|
|
|
- </van-popup>
|
|
|
- <van-popup v-model:show="equipmentIdShow" round position="bottom">
|
|
|
- <van-cascader
|
|
|
- v-model="equipmentIds"
|
|
|
- :title="$t('role.pleaseSelectAPattern')"
|
|
|
- :options="equipmentIdsOptions"
|
|
|
- @close="equipmentIdShow = false"
|
|
|
- @finish="onEquipmentIdFinish"
|
|
|
- />
|
|
|
- </van-popup> -->
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -49,9 +79,8 @@
|
|
|
import { onMounted, reactive, toRefs, ref } from "vue";
|
|
|
import sHeader from "../../components/SimpleHeader";
|
|
|
import { showFailToast, showSuccessToast } from "vant";
|
|
|
-// import { getSysRoleList, getEquipmentList } from "../../service/accountPar/index";
|
|
|
import { addSysRole, updateSysRole } from "../../service/role/index";
|
|
|
-import { getLoginUser, $M_Menus, styleUrl } from "../../common/js/utils";
|
|
|
+import { getLoginUser, $M_Menus, remoteMenus } from "../../common/js/utils";
|
|
|
import { useRouter } from "vue-router";
|
|
|
import { useI18n } from "vue-i18n";
|
|
|
|
|
@@ -66,100 +95,105 @@ export default {
|
|
|
const roleName = ref("");
|
|
|
// 设置的权限
|
|
|
const menuCodeList = ref([]);
|
|
|
+ const remoteCodeList = ref([]);
|
|
|
+
|
|
|
const roleMenuCode = ref([]);
|
|
|
- // const roleShow = ref(false);
|
|
|
+ const controlCode = ref([]);
|
|
|
+
|
|
|
const roleText = ref("");
|
|
|
- // const roleOptions = ref([]);
|
|
|
- // const onRoleFinish = ({ selectedOptions }) => {
|
|
|
- // roleShow.value = false;
|
|
|
- // roleText.value = selectedOptions[0].text;
|
|
|
- // };
|
|
|
- // const equipmentIdShow = ref(false);
|
|
|
const equipmentIdText = ref("");
|
|
|
const equipmentIdsOptions = ref([]);
|
|
|
- // const onEquipmentIdFinish = ({ selectedOptions }) => {
|
|
|
- // equipmentIdShow.value = false;
|
|
|
- // equipmentIdText.value = selectedOptions[0].text;
|
|
|
- // };
|
|
|
+
|
|
|
+ // 全选/反选逻辑
|
|
|
+ const toggleAll = (checked) => {
|
|
|
+ const allCommon = menuCodeList.value.map(i => i)
|
|
|
+ const allRemote = remoteCodeList.value.map(i => i)
|
|
|
+
|
|
|
+ roleMenuCode.value = checked ? allCommon : []
|
|
|
+ controlCode.value = checked ? allRemote : []
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分类全选
|
|
|
+ const toggleCategory = (type, checked) => {
|
|
|
+ const values = type === 'common'
|
|
|
+ ? menuCodeList.value.map(i => i)
|
|
|
+ : remoteCodeList.value.map(i => i)
|
|
|
+
|
|
|
+ if (type === 'common') {
|
|
|
+ roleMenuCode.value = checked ? values : []
|
|
|
+ } else {
|
|
|
+ controlCode.value = checked ? values : []
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
let addParams = reactive({
|
|
|
username: "",
|
|
|
password: "",
|
|
|
name: "",
|
|
|
phone: "",
|
|
|
isEnabled: true,
|
|
|
- // roleList: "",
|
|
|
equipmentIds: "",
|
|
|
});
|
|
|
let roleItem = null;
|
|
|
onMounted(async () => {
|
|
|
// 加载样式
|
|
|
- styleUrl('role');
|
|
|
roleItem = localStorage.getItem("roleItem");
|
|
|
if (roleItem) {
|
|
|
roleItem = JSON.parse(roleItem);
|
|
|
roleName.value = roleItem.roleName;
|
|
|
roleMenuCode.value = roleItem.menuCodesJson;
|
|
|
+ controlCode.value = roleItem.controlCodesJson;
|
|
|
pageTitle.value = t("role.modifyRole");
|
|
|
} else {
|
|
|
pageTitle.value = t("role.addRole");
|
|
|
}
|
|
|
- // 设置菜单权限
|
|
|
menuSet();
|
|
|
- // getSysRoleListFun();
|
|
|
- // getEquipmentListFun();
|
|
|
});
|
|
|
// 设置菜单权限
|
|
|
const menuSet = () => {
|
|
|
- // 如果不是admin管理员权限type=0,要删除 广告管理M5,杉德分账M10,系统脱机M17,apk管理M19
|
|
|
if (user.type !== 0) {
|
|
|
delete $M_Menus['M5'];
|
|
|
delete $M_Menus['M10'];
|
|
|
delete $M_Menus['M17'];
|
|
|
delete $M_Menus['M19'];
|
|
|
+ delete $M_Menus['M21'];
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ delete remoteMenus['C19'];
|
|
|
+ delete remoteMenus['C20'];
|
|
|
+ delete remoteMenus['C21'];
|
|
|
+ delete remoteMenus['C22'];
|
|
|
+ delete remoteMenus['C23'];
|
|
|
}
|
|
|
// 如果是商家,进一步删除 账户操作M3,订单导出M9,
|
|
|
if (user.type === 2) {
|
|
|
delete $M_Menus['M3'];
|
|
|
delete $M_Menus['M9'];
|
|
|
+ delete $M_Menus['M22'];
|
|
|
}
|
|
|
|
|
|
- for (const key in $M_Menus) {
|
|
|
- console.log(key);
|
|
|
- if (key === "M21") {
|
|
|
- continue;
|
|
|
+ if (user.type === 2) {
|
|
|
+ if (user.ifForeign === "1") {
|
|
|
+ // 国外账号
|
|
|
+ delete remoteMenus['C10'];
|
|
|
+ }
|
|
|
+ if (user.ifForeign === "0") {
|
|
|
+
|
|
|
+ // 国内账号
|
|
|
+ delete delete remoteMenus['C18'];
|
|
|
}
|
|
|
- menuCodeList.value.push({
|
|
|
- label: $M_Menus[key],
|
|
|
- value: key
|
|
|
- });
|
|
|
}
|
|
|
- };
|
|
|
- // 获取角色下拉列表
|
|
|
- // const getSysRoleListFun = async () => {
|
|
|
- // const { data } = await getSysRoleList();
|
|
|
- // if (data.code === "00000") {
|
|
|
- // roleOptions.value = data.data.map((item) => {
|
|
|
- // return { text: item.label, value: item.value };
|
|
|
- // });
|
|
|
- // } else {
|
|
|
- // showFailToast(data.message);
|
|
|
- // }
|
|
|
- // };
|
|
|
- // 获取机器下拉
|
|
|
- // const getEquipmentListFun = async () => {
|
|
|
- // const { data } = await getEquipmentList({ adminId: user.id });
|
|
|
- // if (data.code === "00000") {
|
|
|
- // equipmentIdsOptions.value = data.data.map((item) => {
|
|
|
- // return { text: item.name, value: item.id };
|
|
|
- // });
|
|
|
- // equipmentIdsOptions.value.unshift({
|
|
|
- // text: t("role.whole"),
|
|
|
- // value: "all",
|
|
|
- // });
|
|
|
- // } else {
|
|
|
- // showFailToast(data.message);
|
|
|
- // }
|
|
|
- // };
|
|
|
+
|
|
|
+ for (const key in $M_Menus) {
|
|
|
+ menuCodeList.value.push(key);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const key in remoteMenus) {
|
|
|
+ remoteCodeList.value.push(key);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
const onSubmit = async () => {
|
|
|
if (roleItem) {
|
|
@@ -173,16 +207,17 @@ export default {
|
|
|
adminId: user.id,
|
|
|
roleName: roleName.value,
|
|
|
menuCodeList: roleMenuCode.value,
|
|
|
+ controlCodeList: controlCode.value
|
|
|
};
|
|
|
const { data } = await addSysRole(params);
|
|
|
if (data.code === "00000") {
|
|
|
showSuccessToast(t("role.roleAddedSuccessfully"));
|
|
|
- // router.push("/role");
|
|
|
- router.go(-1);
|
|
|
+ setTimeout(() => {
|
|
|
+ router.go(-1);
|
|
|
+ }, 1000);
|
|
|
} else {
|
|
|
showFailToast(`${t("role.failedToAddRole")} ${data.message}`);
|
|
|
}
|
|
|
- console.log("onSubmit", data);
|
|
|
};
|
|
|
const updateSysRoleFun = async () => {
|
|
|
const params = {
|
|
@@ -190,32 +225,33 @@ export default {
|
|
|
roleId: roleItem.roleId,
|
|
|
roleName: roleName.value,
|
|
|
menuCodeList: roleMenuCode.value,
|
|
|
+ controlCodeList: controlCode.value
|
|
|
};
|
|
|
const { data } = await updateSysRole(params);
|
|
|
if (data.code === "00000") {
|
|
|
showSuccessToast(t("role.successfullyModifiedRole"));
|
|
|
- // router.go(-1);
|
|
|
- router.replace("/role");
|
|
|
+ setTimeout(() => {
|
|
|
+ router.go(-1);
|
|
|
+ }, 1000);
|
|
|
} else {
|
|
|
showFailToast(`${t("role.failedToModifyRole")} ${data.message}`);
|
|
|
}
|
|
|
- console.log("onSubmit", data);
|
|
|
};
|
|
|
return {
|
|
|
pageTitle,
|
|
|
roleName,
|
|
|
menuCodeList,
|
|
|
+ remoteCodeList,
|
|
|
roleMenuCode,
|
|
|
- // roleShow,
|
|
|
roleText,
|
|
|
- // roleOptions,
|
|
|
- // onRoleFinish,
|
|
|
- // equipmentIdShow,
|
|
|
+ controlCode,
|
|
|
equipmentIdText,
|
|
|
equipmentIdsOptions,
|
|
|
- // onEquipmentIdFinish,
|
|
|
...toRefs(addParams),
|
|
|
onSubmit,
|
|
|
+ menuSet,
|
|
|
+ toggleAll,
|
|
|
+ toggleCategory,
|
|
|
};
|
|
|
},
|
|
|
};
|
|
@@ -223,4 +259,180 @@ export default {
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
@import "../../common/style/common.less";
|
|
|
+
|
|
|
+.role-container {
|
|
|
+ background: #f8faff;
|
|
|
+ min-height: 100vh;
|
|
|
+
|
|
|
+ .bulk-actions {
|
|
|
+ padding: 0 16px 12px;
|
|
|
+ display: flex;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .van-button {
|
|
|
+ flex: 1;
|
|
|
+ border-radius: 14px;
|
|
|
+ background: #f0f3ff;
|
|
|
+ color: #4e6bdd;
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-card {
|
|
|
+ margin: 16px;
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: 0 2px 8px rgba(78, 107, 221, 0.08);
|
|
|
+ }
|
|
|
+
|
|
|
+ .permission-section {
|
|
|
+ padding: 0 16px;
|
|
|
+
|
|
|
+ .permission-card {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 12px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ box-shadow: 0 2px 12px rgba(78, 107, 221, 0.1);
|
|
|
+
|
|
|
+ .card-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 16px;
|
|
|
+ border-bottom: 1px solid #f0f3ff;
|
|
|
+
|
|
|
+ .header-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-grow: 1; // 占据剩余空间
|
|
|
+
|
|
|
+ .card-icon {
|
|
|
+ font-size: 20px;
|
|
|
+ margin-right: 12px;
|
|
|
+ color: #4e6bdd;
|
|
|
+ flex-shrink: 0; // 防止图标被压缩
|
|
|
+
|
|
|
+ &.warn-icon {
|
|
|
+ color: #ff5252;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-title {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #2c3e50;
|
|
|
+ line-height: 1.4;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ bottom: -4px;
|
|
|
+ left: 0;
|
|
|
+ width: 30px;
|
|
|
+ height: 2px;
|
|
|
+ background: #4e6bdd;
|
|
|
+ border-radius: 1px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .header-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 6px;
|
|
|
+
|
|
|
+ .action-btn {
|
|
|
+ height: 24px;
|
|
|
+ padding: 0 8px;
|
|
|
+ border-radius: 12px;
|
|
|
+ background: rgba(255, 255, 255, 0.9);
|
|
|
+ border: 1px solid #eee;
|
|
|
+ font-size: 12px;
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .checkbox-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
|
|
+ gap: 12px;
|
|
|
+ padding: 16px;
|
|
|
+
|
|
|
+ .perm-item {
|
|
|
+ margin: 0;
|
|
|
+ padding: 12px;
|
|
|
+ border: 1px solid #f0f3ff;
|
|
|
+ border-radius: 8px;
|
|
|
+ transition: all 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: #4e6bdd;
|
|
|
+ box-shadow: 0 2px 6px rgba(78, 107, 221, 0.1);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.danger-item {
|
|
|
+ border-color: #ffeaea;
|
|
|
+ background: #fff5f5;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: #ff5252;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.van-checkbox__label) {
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-start;
|
|
|
+ }
|
|
|
+
|
|
|
+ .perm-label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #34495e;
|
|
|
+ line-height: 1.4;
|
|
|
+ }
|
|
|
+
|
|
|
+ .perm-desc {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ margin-top: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .perm-warn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #ff5252;
|
|
|
+ margin-top: 6px;
|
|
|
+
|
|
|
+ .warn-icon {
|
|
|
+ margin-right: 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .submit-footer {
|
|
|
+ padding: 24px 16px;
|
|
|
+
|
|
|
+ .submit-btn {
|
|
|
+ height: 44px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ background: linear-gradient(135deg, #4e6bdd, #3b5ab3);
|
|
|
+ border: none;
|
|
|
+ box-shadow: 0 4px 12px rgba(78, 107, 221, 0.2);
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ opacity: 0.9;
|
|
|
+ transform: scale(0.98);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|