Procházet zdrojové kódy

perf(views): 初步编写"角色管理"页面

wangshun před 2 týdny
rodič
revize
2b76f6f3b4
1 změnil soubory, kde provedl 376 přidání a 1 odebrání
  1. 376 1
      src/views/role-manage/RoleManage.vue

+ 376 - 1
src/views/role-manage/RoleManage.vue

@@ -1,3 +1,378 @@
+<script setup lang="ts">
+import { nextTick, onMounted, ref } from 'vue';
+import { message } from 'ant-design-vue';
+
+import OrganizationalStructure from '@/components/OrganizationalStructure.vue';
+import SvgIcon from '@/components/SvgIcon.vue';
+import { useRequest } from '@/hooks/request';
+import { getSubOrgsByToken } from '@/api';
+
+import type { DataNode } from 'ant-design-vue/es/tree';
+
+const characterList = ref([
+  {
+    name: '管理员',
+    id: 1,
+    show: false,
+  },
+  {
+    name: '工程师',
+    id: 2,
+    show: false,
+  },
+  {
+    name: '技术员',
+    id: 3,
+    show: false,
+  },
+  {
+    name: '操作工',
+    id: 4,
+    show: false,
+  },
+]);
+const { handleRequest } = useRequest();
+const characterListId = ref(1);
+const inputRef = ref<HTMLInputElement[]>([]); // 明确的类型声明
+const permissions = ref<string>('dataPermissions');
+const equipmentChecked = ref<boolean>(false);
+const editorChecked = ref<boolean>(true);
+const valueTime = ref<string>('1');
+const pagePermissionsSelectedKeys = ref<number[]>([]);
+
+const pagePermissionsTree = ref<DataNode[]>([
+  {
+    title: '父节点 1',
+    key: '0-0',
+    children: [
+      {
+        title: '子节点 1',
+        key: '0-0-0',
+        children: [
+          { title: '孙子节点 1', key: '0-0-0-0' },
+          { title: '孙子节点 2', key: '0-0-0-1' },
+        ],
+      },
+      { title: '子节点 2', key: '0-0-1' },
+    ],
+  },
+]);
+const addCharacter = async () => {
+  if (characterList.value.some((item) => item.name === '')) {
+    return;
+  }
+  characterList.value.push({
+    name: '',
+    id: 5,
+    show: true,
+  });
+  await nextTick();
+  console.log(inputRef.value);
+  inputRef.value[0].focus();
+};
+const clickCharacter = (id: number) => {
+  if (characterList.value.some((item) => item.name === '')) {
+    return;
+  }
+
+  characterListId.value = id;
+};
+const addEditor = async (index: number) => {
+  if (characterList.value.some((item) => item.name === '')) {
+    return;
+  }
+  characterList.value[index].show = true;
+  await nextTick();
+  inputRef.value[0].focus();
+};
+const editorcharacter = (index: number, name: string) => {
+  if (name) {
+    characterList.value[index].show = false;
+  } else {
+    return message.warning('名称不能为空!');
+  }
+};
+const editorPermission = () => {
+  editorChecked.value = false;
+};
+const cancelPermission = () => {
+  editorChecked.value = true;
+};
+const savePermission = () => {
+  editorChecked.value = true;
+};
+const clickOrganizationChange = (id: number) => {
+  console.log(id);
+};
+
+onMounted(() => {
+  handleRequest(async () => {
+    await getSubOrgsByToken();
+  });
+});
+</script>
+
 <template>
-  <div>角色管理</div>
+  <div>
+    <div class="text-top">角色管理</div>
+    <AFlex>
+      <OrganizationalStructure @change="clickOrganizationChange" />
+      <div class="content">
+        <AFlex justify="space-between" align="center" class="content-top">
+          <div class="content-text">角色</div>
+          <div class="icon-style pointer" @click="addCharacter">
+            <AFlex align="center"
+              ><SvgIcon name="plus" />
+              <div class="text-left">添加</div>
+            </AFlex>
+          </div>
+        </AFlex>
+        <div>
+          <div v-for="(item, index) in characterList" :key="index">
+            <div class="character-input" v-if="item.show">
+              <AInput
+                class="input-heught"
+                v-model:value="item.name"
+                :bordered="false"
+                ref="inputRef"
+                @pressEnter="editorcharacter(index, item.name)"
+                @blur="editorcharacter(index, item.name)"
+              />
+            </div>
+            <AFlex
+              v-else
+              justify="space-between"
+              align="center"
+              :class="item.id === characterListId ? 'character-list character-list-color' : 'character-list'"
+            >
+              <div class="pointer text-height" @click="clickCharacter(item.id)">{{ item.name }}</div>
+              <div v-if="item.id === characterListId">
+                <SvgIcon class="pointer" name="edit-o" @click="addEditor(index)" />
+                <SvgIcon class="pointer icon-left" name="delete" />
+              </div>
+            </AFlex>
+          </div>
+        </div>
+      </div>
+
+      <div class="permission-management">
+        <AFlex justify="space-between" align="center" class="content-top">
+          <div class="content-text">权限</div>
+          <div class="pointer" @click="editorPermission" v-if="editorChecked">
+            <AFlex align="center"
+              ><SvgIcon name="edit-o" />
+              <div class="text-left">编辑</div>
+            </AFlex>
+          </div>
+          <AFlex v-else>
+            <div class="pointer" @click="cancelPermission">
+              <AFlex align="center"
+                ><SvgIcon name="close" />
+                <div class="text-left">取消</div>
+              </AFlex>
+            </div>
+            <div class="pointer pointer-left" @click="savePermission">
+              <AFlex align="center"
+                ><SvgIcon name="close" />
+                <div class="text-left">保存</div>
+              </AFlex>
+            </div>
+          </AFlex>
+        </AFlex>
+
+        <ARadioGroup v-model:value="permissions" button-style="solid" size="large">
+          <ARadioButton value="dataPermissions">数据权限</ARadioButton>
+          <ARadioButton value="functionPermissions">功能权限</ARadioButton>
+        </ARadioGroup>
+        <div v-if="permissions === 'dataPermissions'">
+          <AFlex align="center" class="device-permissions">
+            <ACheckbox class="select-all" v-model:checked="equipmentChecked" :disabled="editorChecked"
+              >设备组权限</ACheckbox
+            >
+          </AFlex>
+          <ATree
+            v-model:selected-keys="pagePermissionsSelectedKeys"
+            :tree-data="pagePermissionsTree"
+            checkable
+            default-expand-all
+            :disabled="editorChecked"
+          />
+          <AFlex align="center" class="device-permissions div-top">
+            <ACheckbox class="select-all" :disabled="editorChecked" v-model:checked="equipmentChecked"
+              >启用时间查询颗粒度设置</ACheckbox
+            >
+          </AFlex>
+          <ARadioGroup v-model:value="valueTime" name="radioGroup" class="radio-group" :disabled="editorChecked">
+            <ARadio value="1">分钟</ARadio>
+            <ARadio value="2">小时</ARadio>
+            <ARadio value="3">天</ARadio>
+            <ARadio value="4">月</ARadio>
+          </ARadioGroup>
+        </div>
+        <div v-if="permissions === 'functionPermissions'">
+          <AFlex align="center" class="device-permissions">
+            <div>查看权限</div>
+          </AFlex>
+          <ATree
+            v-model:selected-keys="pagePermissionsSelectedKeys"
+            :tree-data="pagePermissionsTree"
+            checkable
+            default-expand-all
+            class="tree-permissions"
+            :disabled="editorChecked"
+          />
+          <AFlex align="center" class="device-permissions div-top">
+            <div>操作权限</div>
+          </AFlex>
+        </div>
+      </div>
+    </AFlex>
+  </div>
 </template>
+
+<style lang="scss" scoped>
+.pointer-left {
+  margin-left: 24px;
+}
+
+:deep(.permission-management) {
+  .ant-tree-list-holder-inner > div {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    height: 48px;
+    padding-left: 26px;
+  }
+
+  .tree-permissions .ant-tree-list-holder-inner > div {
+    border-bottom: 1px solid #e4e7ed;
+  }
+
+  .ant-tree-list-holder-inner > div > .ant-tree-checkbox {
+    margin-block-start: 0;
+  }
+
+  .ant-tree-list-holder-inner > div > .ant-tree-switcher > span {
+    margin-top: 16px;
+  }
+}
+
+.radio-group {
+  margin-top: 13px;
+  margin-left: 48px;
+}
+
+:deep(.radio-group) {
+  .ant-radio-wrapper {
+    margin-inline-end: 20px;
+  }
+}
+
+.device-permissions {
+  width: 100%;
+  height: 48px;
+  padding-left: 24px;
+  margin-top: 16px;
+  background: #f5f7fa;
+  border-radius: 4px;
+}
+
+.permission-management .div-top {
+  margin-top: 0;
+}
+
+.permission-management {
+  width: 100%;
+  height: calc(100vh - 80px);
+  padding: 16px;
+  background: #fff;
+  border-radius: 16px;
+}
+
+.input-heught {
+  height: 38px;
+}
+
+.character-input {
+  width: 214px;
+  height: 40px;
+  background: rgb(255 255 255 / 15%);
+  border: 1px solid var(--antd-color-primary);
+  border-radius: 4px;
+}
+
+.text-left {
+  margin-left: 10px;
+}
+
+.icon-style {
+  color: var(--antd-color-primary);
+}
+
+.text-height {
+  height: 40px;
+  line-height: 40px;
+}
+
+.icon-left {
+  margin-left: 13px;
+}
+
+.pointer {
+  cursor: pointer;
+}
+
+.character-list {
+  width: 214px;
+  height: 40px;
+  padding: 0 12px;
+  font-size: 14px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 22px;
+  color: #000;
+  text-align: left;
+  border-radius: 4px;
+}
+
+.character-list-color {
+  color: var(--antd-color-primary);
+  background: var(--antd-color-primary-opacity-15);
+}
+
+.content-top {
+  margin-bottom: 16px;
+}
+
+.button-style {
+  color: var(--antd-color-primary);
+}
+
+.content-text {
+  font-size: 16px;
+  font-style: normal;
+  font-weight: 600;
+  line-height: 24px;
+  color: #333;
+  text-align: left;
+}
+
+.content {
+  width: 246px;
+  height: calc(100vh - 80px);
+  padding: 16px;
+  margin-right: 16px;
+  background: #fff;
+  border-radius: 16px;
+}
+
+.text-top {
+  margin-bottom: 16px;
+  font-size: 20px;
+  font-style: normal;
+  font-weight: 500;
+  line-height: 32px;
+  color: rgb(0 0 0 / 85%);
+  text-align: left;
+}
+</style>