mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-11-04 10:57:08 +08:00 
			
		
		
		
	refactor: eslint src --fix
This commit is contained in:
		@@ -6,4 +6,4 @@ const BASE_URL = '/captcha'
 | 
			
		||||
/** @desc 获取图片验证码 */
 | 
			
		||||
export function getImageCaptcha() {
 | 
			
		||||
  return http.get<Common.ImageCaptchaResp>(`${BASE_URL}/img`)
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import http from '@/utils/http'
 | 
			
		||||
import type { LabelValueState } from '@/types/global'
 | 
			
		||||
import type { TreeNodeData } from '@arco-design/web-vue'
 | 
			
		||||
import type {OptionQuery} from '@/apis'
 | 
			
		||||
import type { OptionQuery } from '@/apis'
 | 
			
		||||
 | 
			
		||||
const BASE_URL = '/common'
 | 
			
		||||
 | 
			
		||||
@@ -33,4 +33,4 @@ export function listOption(params: OptionQuery) {
 | 
			
		||||
/** @desc 上传文件 */
 | 
			
		||||
export function uploadFile(data: FormData) {
 | 
			
		||||
  return http.post(`${BASE_URL}/file`, data)
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,4 +9,3 @@ export * from './auth/type'
 | 
			
		||||
export * from './common/type'
 | 
			
		||||
export * from './monitor/type'
 | 
			
		||||
export * from './system/type'
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ export interface LogDetailResp extends LogResp {
 | 
			
		||||
  responseHeaders: string
 | 
			
		||||
  responseBody: string
 | 
			
		||||
}
 | 
			
		||||
export interface LogQuery{
 | 
			
		||||
export interface LogQuery {
 | 
			
		||||
  description?: string
 | 
			
		||||
  module?: string
 | 
			
		||||
  ip?: string
 | 
			
		||||
 
 | 
			
		||||
@@ -221,4 +221,4 @@ export interface BasicConfigRecordResp {
 | 
			
		||||
  site_copyright?: string
 | 
			
		||||
  site_logo?: string
 | 
			
		||||
  site_favicon?: string
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,11 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <span v-if="!dictItem"></span>
 | 
			
		||||
  <span v-else-if="!dictItem.color">{{ dictItem.label }}</span>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'primary'" color="arcoblue">{{
 | 
			
		||||
      dictItem.label
 | 
			
		||||
    }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'success'" color="green">{{
 | 
			
		||||
      dictItem.label
 | 
			
		||||
    }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'warning'" color="orangered">{{
 | 
			
		||||
      dictItem.label
 | 
			
		||||
    }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'error'" color="red">{{
 | 
			
		||||
      dictItem.label
 | 
			
		||||
    }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'default'" color="gray">{{
 | 
			
		||||
      dictItem.label
 | 
			
		||||
    }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'primary'" color="arcoblue">{{ dictItem.label }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'success'" color="green">{{ dictItem.label }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'warning'" color="orangered">{{ dictItem.label }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'error'" color="red">{{ dictItem.label }}</a-tag>
 | 
			
		||||
  <a-tag v-else-if="dictItem.color === 'default'" color="gray">{{ dictItem.label }}</a-tag>
 | 
			
		||||
  <a-tag v-else :color="dictItem.color">{{ dictItem.label }}</a-tag>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -27,19 +17,17 @@ defineOptions({ name: 'GiCellTag' })
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  dict: {
 | 
			
		||||
    type: Array<LabelValueState>,
 | 
			
		||||
    required: true,
 | 
			
		||||
    required: true
 | 
			
		||||
  },
 | 
			
		||||
  value: {
 | 
			
		||||
    type: [Number, String],
 | 
			
		||||
    required: true,
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
    required: true
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const dictItem = computed(() =>
 | 
			
		||||
  props.dict.find(
 | 
			
		||||
    (d) => d.value === String(props.value) || d.value === Number(props.value),
 | 
			
		||||
  ),
 | 
			
		||||
);
 | 
			
		||||
  props.dict.find((d) => d.value === String(props.value) || d.value === Number(props.value))
 | 
			
		||||
)
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="gi-footer">{{appStore.getCopyright()}}</div>
 | 
			
		||||
  <div class="gi-footer">{{ appStore.getCopyright() }}</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import Dayjs from 'dayjs'
 | 
			
		||||
import {useAppStore} from "@/stores";
 | 
			
		||||
import { useAppStore } from '@/stores'
 | 
			
		||||
 | 
			
		||||
const appStore = useAppStore();
 | 
			
		||||
const appStore = useAppStore()
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'GiFooter' })
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ const searchValue = ref('') // 搜索词
 | 
			
		||||
// 图标列表
 | 
			
		||||
const isGridView = ref(false)
 | 
			
		||||
 | 
			
		||||
let iconList: string[] = []
 | 
			
		||||
const iconList: string[] = []
 | 
			
		||||
for (const path in SvgIconModules) {
 | 
			
		||||
  console.log(path)
 | 
			
		||||
  const name = path.replace('/src/assets/icons/', '').replace('.svg', '')
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="json_pretty_container">
 | 
			
		||||
    <vue-json-pretty
 | 
			
		||||
      :path="'res'"
 | 
			
		||||
      :data="JSONObject"
 | 
			
		||||
      :show-length="true"
 | 
			
		||||
    />
 | 
			
		||||
    <vue-json-pretty :path="'res'" :data="JSONObject" :show-length="true" />
 | 
			
		||||
    <icon-copy class="copy_icon" @click="onCopy(JSONObject)" />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -29,12 +25,12 @@ const onCopy = (data: object) => {
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.json_pretty_container{
 | 
			
		||||
.json_pretty_container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  .copy_icon{
 | 
			
		||||
  .copy_icon {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    right: 10px;
 | 
			
		||||
    top: 10px;
 | 
			
		||||
@@ -42,4 +38,4 @@ const onCopy = (data: object) => {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,15 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="content">
 | 
			
		||||
      <icon-copy :size="16" @click="copyText"/>
 | 
			
		||||
    <icon-copy :size="16" @click="copyText" />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { Message } from "@arco-design/web-vue"
 | 
			
		||||
interface Props{
 | 
			
		||||
  value:any
 | 
			
		||||
import { Message } from '@arco-design/web-vue'
 | 
			
		||||
interface Props {
 | 
			
		||||
  value: any
 | 
			
		||||
}
 | 
			
		||||
const props = withDefaults(defineProps<Props>(), {})
 | 
			
		||||
const copyText=()=>{
 | 
			
		||||
const copyText = () => {
 | 
			
		||||
  const textarea = document.createElement('textarea')
 | 
			
		||||
  textarea.value = props.value
 | 
			
		||||
  document.body.appendChild(textarea)
 | 
			
		||||
@@ -20,9 +20,9 @@ const copyText=()=>{
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.content{
 | 
			
		||||
.content {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  margin-left: 5px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,16 +10,11 @@ import { Message, Notification } from '@arco-design/web-vue'
 | 
			
		||||
interface NavigatorWithMsSaveOrOpenBlob extends Navigator {
 | 
			
		||||
  msSaveOrOpenBlob(blob: Blob, fileName: string): void
 | 
			
		||||
}
 | 
			
		||||
export const useDownload = async (
 | 
			
		||||
  api: () => Promise<any>,
 | 
			
		||||
  isNotify = true,
 | 
			
		||||
  tempName: string = '',
 | 
			
		||||
  fileType = '.xlsx'
 | 
			
		||||
) => {
 | 
			
		||||
export const useDownload = async (api: () => Promise<any>, isNotify = true, tempName = '', fileType = '.xlsx') => {
 | 
			
		||||
  try {
 | 
			
		||||
    const res = await api()
 | 
			
		||||
    if (res.headers['content-disposition']) {
 | 
			
		||||
      tempName = decodeURI(res.headers['content-disposition'].split(';')[1].split('=')[1]);
 | 
			
		||||
      tempName = decodeURI(res.headers['content-disposition'].split(';')[1].split('=')[1])
 | 
			
		||||
    } else {
 | 
			
		||||
      tempName = tempName ? tempName : new Date().getTime() + fileType
 | 
			
		||||
    }
 | 
			
		||||
@@ -36,7 +31,7 @@ export const useDownload = async (
 | 
			
		||||
    const blob = new Blob([res.data])
 | 
			
		||||
    // 兼容 edge 不支持 createObjectURL 方法
 | 
			
		||||
    if ('msSaveOrOpenBlob' in (navigator as unknown as NavigatorWithMsSaveOrOpenBlob)) {
 | 
			
		||||
      ; (window.navigator as unknown as NavigatorWithMsSaveOrOpenBlob).msSaveOrOpenBlob(blob, tempName + fileType)
 | 
			
		||||
      ;(window.navigator as unknown as NavigatorWithMsSaveOrOpenBlob).msSaveOrOpenBlob(blob, tempName + fileType)
 | 
			
		||||
    }
 | 
			
		||||
    const blobUrl = window.URL.createObjectURL(blob)
 | 
			
		||||
    const exportFile = document.createElement('a')
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="system-logo" :class="{ collapsed: props.collapsed }" @click="toHome">
 | 
			
		||||
    <img class="logo" :src="appStore.getLogo() ?? '@/assets/images/logo.svg'"  alt="logo"/>
 | 
			
		||||
    <span class="system-name">{{ appStore.getTitle()}}</span>
 | 
			
		||||
    <img class="logo" :src="appStore.getLogo() ?? '@/assets/images/logo.svg'" alt="logo" />
 | 
			
		||||
    <span class="system-name">{{ appStore.getTitle() }}</span>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import {useAppStore} from "@/stores";
 | 
			
		||||
import { useAppStore } from '@/stores'
 | 
			
		||||
 | 
			
		||||
const appStore= useAppStore();
 | 
			
		||||
const appStore = useAppStore()
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  collapsed?: boolean
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ const mode = computed(() => {
 | 
			
		||||
 | 
			
		||||
// 是否默认展开选中的菜单
 | 
			
		||||
const autoOpenSelected = computed(() => {
 | 
			
		||||
  return ['left', 'mix'].includes(appStore.layout);
 | 
			
		||||
  return ['left', 'mix'].includes(appStore.layout)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 当前页面激活菜单路径,先从路由里面找
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import router from '@/router'
 | 
			
		||||
import {useUserStore, useRouteStore, useAppStore} from '@/stores'
 | 
			
		||||
import { useUserStore, useRouteStore, useAppStore } from '@/stores'
 | 
			
		||||
import { getToken } from '@/utils/auth'
 | 
			
		||||
import { isHttp } from '@/utils/validate'
 | 
			
		||||
 | 
			
		||||
@@ -15,8 +15,8 @@ export const resetHasRouteFlag = () => {
 | 
			
		||||
router.beforeEach(async (to, from, next) => {
 | 
			
		||||
  const userStore = useUserStore()
 | 
			
		||||
  const routeStore = useRouteStore()
 | 
			
		||||
  const appStore = useAppStore();
 | 
			
		||||
  appStore.initWebConfig();
 | 
			
		||||
  const appStore = useAppStore()
 | 
			
		||||
  appStore.initWebConfig()
 | 
			
		||||
 | 
			
		||||
  // 判断该用户是否登录
 | 
			
		||||
  if (getToken()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ const storeSetup = () => {
 | 
			
		||||
  const webConfig = reactive({}) as BasicConfigRecordResp
 | 
			
		||||
 | 
			
		||||
  const getLogo = () => {
 | 
			
		||||
    return webConfig.site_logo;
 | 
			
		||||
    return webConfig.site_logo
 | 
			
		||||
  }
 | 
			
		||||
  const getFavicon = () => {
 | 
			
		||||
    return webConfig.site_favicon
 | 
			
		||||
@@ -26,17 +26,17 @@ const storeSetup = () => {
 | 
			
		||||
 | 
			
		||||
  // 初始化系统配置
 | 
			
		||||
  const initWebConfig = () => {
 | 
			
		||||
     listOption({
 | 
			
		||||
    listOption({
 | 
			
		||||
      code: ['site_title', 'site_copyright', 'site_favicon', 'site_logo']
 | 
			
		||||
    }).then((res) => {
 | 
			
		||||
      const resMap = new Map()
 | 
			
		||||
      res.data.forEach((item) => {
 | 
			
		||||
        resMap.set(item.label, item.value)
 | 
			
		||||
      })
 | 
			
		||||
       webConfig.site_title=resMap.get('site_title');
 | 
			
		||||
       webConfig.site_copyright=resMap.get('site_copyright');
 | 
			
		||||
       webConfig.site_logo=resMap.get('site_logo');
 | 
			
		||||
       webConfig.site_favicon=resMap.get('site_favicon');
 | 
			
		||||
      webConfig.site_title = resMap.get('site_title')
 | 
			
		||||
      webConfig.site_copyright = resMap.get('site_copyright')
 | 
			
		||||
      webConfig.site_logo = resMap.get('site_logo')
 | 
			
		||||
      webConfig.site_favicon = resMap.get('site_favicon')
 | 
			
		||||
      document.title = resMap.get('site_title')
 | 
			
		||||
      document
 | 
			
		||||
        .querySelector('link[rel="shortcut icon"]')
 | 
			
		||||
@@ -46,7 +46,7 @@ const storeSetup = () => {
 | 
			
		||||
 | 
			
		||||
  // 保存系统配置
 | 
			
		||||
  const saveWebConfig = (config: BasicConfigRecordResp) => {
 | 
			
		||||
    Object.assign(webConfig,config)
 | 
			
		||||
    Object.assign(webConfig, config)
 | 
			
		||||
    document.title = config.site_title || ''
 | 
			
		||||
    document
 | 
			
		||||
      .querySelector('link[rel="shortcut icon"]')
 | 
			
		||||
@@ -118,4 +118,4 @@ const storeSetup = () => {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useAppStore = defineStore('app', storeSetup, {persist: true})
 | 
			
		||||
export const useAppStore = defineStore('app', storeSetup, { persist: true })
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								src/types/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/types/global.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -20,7 +20,6 @@ export interface DictState {
 | 
			
		||||
  items: Array<LabelValueState>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** 状态(1:启用;2:禁用) */
 | 
			
		||||
type Status = 1 | 2
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ http.interceptors.response.use(
 | 
			
		||||
  (response: AxiosResponse) => {
 | 
			
		||||
    const { data } = response
 | 
			
		||||
    const { success, code, msg } = data
 | 
			
		||||
    if(response.request.responseType==='blob'){
 | 
			
		||||
    if (response.request.responseType === 'blob') {
 | 
			
		||||
      NProgress.done()
 | 
			
		||||
      return response
 | 
			
		||||
    }
 | 
			
		||||
@@ -186,4 +186,4 @@ const download = <T = any>(url: string, params?: object, config?: AxiosRequestCo
 | 
			
		||||
    ...config
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
export default { get, post, put, patch, del, request, requestNative,download }
 | 
			
		||||
export default { get, post, put, patch, del, request, requestNative, download }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import { isExternal } from "@/utils/validate";
 | 
			
		||||
import { browse, mapTree } from "xe-utils";
 | 
			
		||||
import _ from "lodash";
 | 
			
		||||
import { Message } from "@arco-design/web-vue";
 | 
			
		||||
import { isExternal } from '@/utils/validate'
 | 
			
		||||
import { browse, mapTree } from 'xe-utils'
 | 
			
		||||
import _ from 'lodash'
 | 
			
		||||
import { Message } from '@arco-design/web-vue'
 | 
			
		||||
 | 
			
		||||
export function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
 | 
			
		||||
  return obj[key]
 | 
			
		||||
@@ -76,7 +76,7 @@ export function isEmpty(data: unknown) {
 | 
			
		||||
  if (data === '' || data === 'undefined' || data === undefined || data === null || data === 'null') {
 | 
			
		||||
    return true
 | 
			
		||||
  }
 | 
			
		||||
  return JSON.stringify(data) == '{}' || JSON.stringify(data) == '[]' || JSON.stringify(data) == '[{}]';
 | 
			
		||||
  return JSON.stringify(data) == '{}' || JSON.stringify(data) == '[]' || JSON.stringify(data) == '[{}]'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -243,12 +243,12 @@ export const formatFileSize = (fileSize: number) => {
 | 
			
		||||
  const size = srcSize / 1024 ** index
 | 
			
		||||
  return `${size.toFixed(2)} ${unitArr[index]}`
 | 
			
		||||
}
 | 
			
		||||
export const copyText =(text:any) =>{
 | 
			
		||||
  const textarea = document.createElement('textarea');
 | 
			
		||||
  textarea.value = text;
 | 
			
		||||
  document.body.appendChild(textarea);
 | 
			
		||||
  textarea.select();
 | 
			
		||||
  document.execCommand('copy');
 | 
			
		||||
  document.body.removeChild(textarea);
 | 
			
		||||
export const copyText = (text: any) => {
 | 
			
		||||
  const textarea = document.createElement('textarea')
 | 
			
		||||
  textarea.value = text
 | 
			
		||||
  document.body.appendChild(textarea)
 | 
			
		||||
  textarea.select()
 | 
			
		||||
  document.execCommand('copy')
 | 
			
		||||
  document.body.removeChild(textarea)
 | 
			
		||||
  Message.success('复制成功')
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,16 +22,16 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
interface ImageType {
 | 
			
		||||
  src: string;
 | 
			
		||||
  title: string;
 | 
			
		||||
  link: string;
 | 
			
		||||
  src: string
 | 
			
		||||
  title: string
 | 
			
		||||
  link: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const imageList: ImageType[] = [
 | 
			
		||||
  {
 | 
			
		||||
    src: `https://doc.charles7c.top/img/sponsor/ad/roovps.jpg?${new Date().getTime()}`,
 | 
			
		||||
    title: 'ROOVPS',
 | 
			
		||||
    link: 'https://roovps.com/cart',
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
    link: 'https://roovps.com/cart'
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,7 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
</script>
 | 
			
		||||
<script setup lang="ts"></script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.login-bg {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
          >
 | 
			
		||||
            <h3 class="login-right__title">
 | 
			
		||||
              <img :src="appStore.getLogo()" alt="Logo" height="33" />
 | 
			
		||||
              <span>{{appStore.getTitle()}}</span>
 | 
			
		||||
              <span>{{ appStore.getTitle() }}</span>
 | 
			
		||||
            </h3>
 | 
			
		||||
            <a-form-item field="username">
 | 
			
		||||
              <a-input v-model="form.username" placeholder="请输入用户名" allow-clear>
 | 
			
		||||
@@ -57,25 +57,24 @@
 | 
			
		||||
    <GiThemeBtn class="theme-btn"></GiThemeBtn>
 | 
			
		||||
    <LoginBg></LoginBg>
 | 
			
		||||
 | 
			
		||||
<!--    <div class="footer">
 | 
			
		||||
    <!--    <div class="footer">
 | 
			
		||||
      <div class="beian">
 | 
			
		||||
        <div class="below text" v-html="appStore.getCopyright()"></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>-->
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { getImageCaptcha } from '@/apis'
 | 
			
		||||
import { Message, type FormInstance } from '@arco-design/web-vue'
 | 
			
		||||
import LoginBg from './components/LoginBg/index.vue'
 | 
			
		||||
import {useAppStore, useUserStore} from '@/stores'
 | 
			
		||||
import { useAppStore, useUserStore } from '@/stores'
 | 
			
		||||
import { useStorage } from '@vueuse/core'
 | 
			
		||||
import { useLoading } from '@/hooks'
 | 
			
		||||
import { encryptByRsa } from '@/utils/encrypt'
 | 
			
		||||
 | 
			
		||||
const appStore = useAppStore();
 | 
			
		||||
const appStore = useAppStore()
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'Login' })
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,9 @@ const columns: TableInstance['columns'] = [
 | 
			
		||||
          value: '2'
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      filter: () =>{return true},
 | 
			
		||||
      filter: () => {
 | 
			
		||||
        return true
 | 
			
		||||
      },
 | 
			
		||||
      alignLeft: true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
  <a-drawer v-model:visible="visible" title="日志详情" :width="720" :footer="false">
 | 
			
		||||
    <a-descriptions title="基本信息" :column="2" size="large" class="general-description">
 | 
			
		||||
      <a-descriptions-item label="日志 ID">{{ dataDetail?.id }}</a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="Trace ID" >{{ dataDetail?.traceId }}<TextCopy :value="dataDetail?.traceId" /></a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="Trace ID"
 | 
			
		||||
        >{{ dataDetail?.traceId }}<TextCopy :value="dataDetail?.traceId"
 | 
			
		||||
      /></a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="操作人">{{ dataDetail?.createUserString }}</a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="操作时间">{{ dataDetail?.createTime }}</a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="操作内容">{{ dataDetail?.description }}</a-descriptions-item>
 | 
			
		||||
@@ -16,12 +18,8 @@
 | 
			
		||||
        <a-tag v-else color="red">失败</a-tag>
 | 
			
		||||
      </a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="耗时">
 | 
			
		||||
        <a-tag v-if="dataDetail?.timeTaken > 500" color="red">
 | 
			
		||||
          {{ dataDetail?.timeTaken }}ms
 | 
			
		||||
        </a-tag>
 | 
			
		||||
        <a-tag v-else-if="dataDetail?.timeTaken > 200" color="orange">
 | 
			
		||||
          {{ dataDetail?.timeTaken }}ms
 | 
			
		||||
        </a-tag>
 | 
			
		||||
        <a-tag v-if="dataDetail?.timeTaken > 500" color="red"> {{ dataDetail?.timeTaken }}ms </a-tag>
 | 
			
		||||
        <a-tag v-else-if="dataDetail?.timeTaken > 200" color="orange"> {{ dataDetail?.timeTaken }}ms </a-tag>
 | 
			
		||||
        <a-tag v-else color="green">{{ dataDetail?.timeTaken }} ms</a-tag>
 | 
			
		||||
      </a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="请求 URI" :span="2">
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
        <a-tab-pane key="2" title="操作日志" />
 | 
			
		||||
      </a-tabs>
 | 
			
		||||
      <keep-alive>
 | 
			
		||||
          <component :is="PaneMap[activeKey]" />
 | 
			
		||||
        <component :is="PaneMap[activeKey]" />
 | 
			
		||||
      </keep-alive>
 | 
			
		||||
    </a-card>
 | 
			
		||||
  </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="page">
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="page"></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
@@ -10,7 +9,6 @@ defineOptions({ name: 'Notification' })
 | 
			
		||||
 | 
			
		||||
const route = useRoute()
 | 
			
		||||
const form = reactive({ name: '' })
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,6 @@ defineOptions({ name: 'Profile' })
 | 
			
		||||
 | 
			
		||||
const route = useRoute()
 | 
			
		||||
const userStore = useUserStore()
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="page">
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="page"></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
@@ -10,7 +9,6 @@ defineOptions({ name: 'Security' })
 | 
			
		||||
 | 
			
		||||
const route = useRoute()
 | 
			
		||||
const form = reactive({ name: '' })
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,32 +6,32 @@
 | 
			
		||||
          {{ siteFavicon?.name }}
 | 
			
		||||
          <template #extra>
 | 
			
		||||
            {{ siteFavicon?.description }}
 | 
			
		||||
            <br/>
 | 
			
		||||
            <br />
 | 
			
		||||
            <a-upload
 | 
			
		||||
                :file-list="faviconFile ? [faviconFile] : []"
 | 
			
		||||
                accept="image/*"
 | 
			
		||||
                :show-file-list="false"
 | 
			
		||||
                :custom-request="handleUploadFavicon"
 | 
			
		||||
                @change="handleChangeFavicon"
 | 
			
		||||
              :file-list="faviconFile ? [faviconFile] : []"
 | 
			
		||||
              accept="image/*"
 | 
			
		||||
              :show-file-list="false"
 | 
			
		||||
              :custom-request="handleUploadFavicon"
 | 
			
		||||
              @change="handleChangeFavicon"
 | 
			
		||||
            >
 | 
			
		||||
              <template #upload-button>
 | 
			
		||||
                <div
 | 
			
		||||
                    :class="`arco-upload-list-item${
 | 
			
		||||
                  :class="`arco-upload-list-item${
 | 
			
		||||
                    faviconFile && faviconFile.status === 'error' ? ' arco-upload-list-item-error' : ''
 | 
			
		||||
                  }`"
 | 
			
		||||
                >
 | 
			
		||||
                  <div
 | 
			
		||||
                      v-if="faviconFile && faviconFile.url"
 | 
			
		||||
                      class="arco-upload-list-picture custom-upload-avatar favicon"
 | 
			
		||||
                    v-if="faviconFile && faviconFile.url"
 | 
			
		||||
                    class="arco-upload-list-picture custom-upload-avatar favicon"
 | 
			
		||||
                  >
 | 
			
		||||
                    <img :src="faviconFile.url" alt="favicon"/>
 | 
			
		||||
                    <img :src="faviconFile.url" alt="favicon" />
 | 
			
		||||
                    <div v-if="isEdit" class="arco-upload-list-picture-mask favicon">
 | 
			
		||||
                      <IconEdit/>
 | 
			
		||||
                      <IconEdit />
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div v-else class="arco-upload-picture-card favicon">
 | 
			
		||||
                    <div class="arco-upload-picture-card-text">
 | 
			
		||||
                      <icon-upload/>
 | 
			
		||||
                      <icon-upload />
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
@@ -45,29 +45,29 @@
 | 
			
		||||
          {{ siteLogo?.name }}
 | 
			
		||||
          <template #extra>
 | 
			
		||||
            {{ siteLogo?.description }}
 | 
			
		||||
            <br/>
 | 
			
		||||
            <br />
 | 
			
		||||
            <a-upload
 | 
			
		||||
                :file-list="logoFile ? [logoFile] : []"
 | 
			
		||||
                accept="image/*"
 | 
			
		||||
                :show-file-list="false"
 | 
			
		||||
                :custom-request="handleUploadLogo"
 | 
			
		||||
                @change="handleChangeLogo"
 | 
			
		||||
              :file-list="logoFile ? [logoFile] : []"
 | 
			
		||||
              accept="image/*"
 | 
			
		||||
              :show-file-list="false"
 | 
			
		||||
              :custom-request="handleUploadLogo"
 | 
			
		||||
              @change="handleChangeLogo"
 | 
			
		||||
            >
 | 
			
		||||
              <template #upload-button>
 | 
			
		||||
                <div
 | 
			
		||||
                    :class="`arco-upload-list-item${
 | 
			
		||||
                  :class="`arco-upload-list-item${
 | 
			
		||||
                    logoFile && logoFile.status === 'error' ? ' arco-upload-list-item-error' : ''
 | 
			
		||||
                  }`"
 | 
			
		||||
                >
 | 
			
		||||
                  <div v-if="logoFile && logoFile.url" class="arco-upload-list-picture custom-upload-avatar logo">
 | 
			
		||||
                    <img :src="logoFile.url" alt="Logo"/>
 | 
			
		||||
                    <img :src="logoFile.url" alt="Logo" />
 | 
			
		||||
                    <div v-if="isEdit" class="arco-upload-list-picture-mask logo">
 | 
			
		||||
                      <IconEdit/>
 | 
			
		||||
                      <IconEdit />
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div v-else class="arco-upload-picture-card logo">
 | 
			
		||||
                    <div class="arco-upload-picture-card-text">
 | 
			
		||||
                      <icon-upload/>
 | 
			
		||||
                      <icon-upload />
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
@@ -78,47 +78,47 @@
 | 
			
		||||
      </a-list-item>
 | 
			
		||||
      <a-list-item style="padding-top: 13px; border: none">
 | 
			
		||||
        <a-form-item class="input-item" :label="siteTitle?.name" field="site_title">
 | 
			
		||||
          <a-input v-model="form.site_title" placeholder="请输入网站标题" :max-length="18"/>
 | 
			
		||||
          <a-input v-model="form.site_title" placeholder="请输入网站标题" :max-length="18" />
 | 
			
		||||
        </a-form-item>
 | 
			
		||||
        <a-form-item class="input-item" :label="siteCopyright?.name" field="site_copyright" tooltip="支持HTML标签">
 | 
			
		||||
          <a-textarea
 | 
			
		||||
              v-model="form.site_copyright"
 | 
			
		||||
              placeholder="请输入版权信息"
 | 
			
		||||
              :auto-size="{
 | 
			
		||||
            v-model="form.site_copyright"
 | 
			
		||||
            placeholder="请输入版权信息"
 | 
			
		||||
            :auto-size="{
 | 
			
		||||
              minRows: 3
 | 
			
		||||
            }"
 | 
			
		||||
              show-word-limit
 | 
			
		||||
            show-word-limit
 | 
			
		||||
          />
 | 
			
		||||
        </a-form-item>
 | 
			
		||||
        <div style="margin-top: 20px">
 | 
			
		||||
          <a-space>
 | 
			
		||||
            <a-button v-if="!isEdit" @click="toResetValue">
 | 
			
		||||
              <template #icon>
 | 
			
		||||
                <icon-undo/>
 | 
			
		||||
                <icon-undo />
 | 
			
		||||
              </template>
 | 
			
		||||
              恢复默认
 | 
			
		||||
            </a-button>
 | 
			
		||||
            <a-button v-if="!isEdit" type="primary" @click="toEdit">
 | 
			
		||||
              <template #icon>
 | 
			
		||||
                <icon-edit/>
 | 
			
		||||
                <icon-edit />
 | 
			
		||||
              </template>
 | 
			
		||||
              修改
 | 
			
		||||
            </a-button>
 | 
			
		||||
            <a-button v-if="isEdit" type="primary" @click="handleSave">
 | 
			
		||||
              <template #icon>
 | 
			
		||||
                <icon-save/>
 | 
			
		||||
                <icon-save />
 | 
			
		||||
              </template>
 | 
			
		||||
              保存
 | 
			
		||||
            </a-button>
 | 
			
		||||
            <a-button v-if="isEdit" @click="reset">
 | 
			
		||||
              <template #icon>
 | 
			
		||||
                <icon-refresh/>
 | 
			
		||||
                <icon-refresh />
 | 
			
		||||
              </template>
 | 
			
		||||
              重置
 | 
			
		||||
            </a-button>
 | 
			
		||||
            <a-button v-if="isEdit" @click="handleCancel">
 | 
			
		||||
              <template #icon>
 | 
			
		||||
                <icon-undo/>
 | 
			
		||||
                <icon-undo />
 | 
			
		||||
              </template>
 | 
			
		||||
              取消
 | 
			
		||||
            </a-button>
 | 
			
		||||
@@ -130,17 +130,17 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import type {OptionResp} from '@/apis'
 | 
			
		||||
import {list, resetValue, save, uploadFile} from '@/apis'
 | 
			
		||||
import {useAppStore} from '@/stores'
 | 
			
		||||
import {type FileItem, type FormInstance, type RequestOption, Message, Modal} from '@arco-design/web-vue'
 | 
			
		||||
import {useForm} from '@/hooks'
 | 
			
		||||
import type { OptionResp } from '@/apis'
 | 
			
		||||
import { list, resetValue, save, uploadFile } from '@/apis'
 | 
			
		||||
import { useAppStore } from '@/stores'
 | 
			
		||||
import { type FileItem, type FormInstance, type RequestOption, Message, Modal } from '@arco-design/web-vue'
 | 
			
		||||
import { useForm } from '@/hooks'
 | 
			
		||||
 | 
			
		||||
const formRef = ref<FormInstance>()
 | 
			
		||||
const dataList = ref<OptionResp[]>([])
 | 
			
		||||
const isEdit = ref(false)
 | 
			
		||||
const logoFile = ref<FileItem>({uid: '-1'})
 | 
			
		||||
const faviconFile = ref<FileItem>({uid: '-2'})
 | 
			
		||||
const logoFile = ref<FileItem>({ uid: '-1' })
 | 
			
		||||
const faviconFile = ref<FileItem>({ uid: '-2' })
 | 
			
		||||
const siteTitle = ref<OptionResp>()
 | 
			
		||||
const siteCopyright = ref<OptionResp>()
 | 
			
		||||
const siteLogo = ref<OptionResp>()
 | 
			
		||||
@@ -148,11 +148,11 @@ const siteFavicon = ref<OptionResp>()
 | 
			
		||||
const appStore = useAppStore()
 | 
			
		||||
 | 
			
		||||
const rules: FormInstance['rules'] = {
 | 
			
		||||
  site_title: [{required: true, message: '请输入系统标题'}],
 | 
			
		||||
  site_copyright: [{required: true, message: '请输入版权信息'}]
 | 
			
		||||
  site_title: [{ required: true, message: '请输入系统标题' }],
 | 
			
		||||
  site_copyright: [{ required: true, message: '请输入版权信息' }]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const {form} = useForm({
 | 
			
		||||
const { form } = useForm({
 | 
			
		||||
  site_title: '',
 | 
			
		||||
  site_copyright: '',
 | 
			
		||||
  site_logo: '',
 | 
			
		||||
@@ -169,10 +169,10 @@ const query = reactive({
 | 
			
		||||
 * 重置表单
 | 
			
		||||
 */
 | 
			
		||||
const reset = () => {
 | 
			
		||||
  form.site_title=siteTitle.value?.value || '';
 | 
			
		||||
  form.site_copyright= siteCopyright.value?.value || '';
 | 
			
		||||
  form.site_logo= siteLogo.value?.value || '';
 | 
			
		||||
  form. site_favicon=siteFavicon.value?.value || ''
 | 
			
		||||
  form.site_title = siteTitle.value?.value || ''
 | 
			
		||||
  form.site_copyright = siteCopyright.value?.value || ''
 | 
			
		||||
  form.site_logo = siteLogo.value?.value || ''
 | 
			
		||||
  form.site_favicon = siteFavicon.value?.value || ''
 | 
			
		||||
  logoFile.value.url = siteLogo.value?.value
 | 
			
		||||
  faviconFile.value.url = siteFavicon.value?.value
 | 
			
		||||
}
 | 
			
		||||
@@ -226,21 +226,21 @@ const handleSave = () => {
 | 
			
		||||
 * @param options /
 | 
			
		||||
 */
 | 
			
		||||
const handleUploadLogo = (options: RequestOption) => {
 | 
			
		||||
  const controller = new AbortController();
 | 
			
		||||
  (async function requestWrap() {
 | 
			
		||||
    const {onProgress, onError, onSuccess, fileItem, name = 'file'} = options
 | 
			
		||||
  const controller = new AbortController()
 | 
			
		||||
  ;(async function requestWrap() {
 | 
			
		||||
    const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options
 | 
			
		||||
    onProgress(20)
 | 
			
		||||
    const formData = new FormData()
 | 
			
		||||
    formData.append(name as string, fileItem.file as Blob)
 | 
			
		||||
    uploadFile(formData)
 | 
			
		||||
        .then((res) => {
 | 
			
		||||
          onSuccess(res)
 | 
			
		||||
          form.site_logo = res.data.url
 | 
			
		||||
          Message.success(res.msg)
 | 
			
		||||
        })
 | 
			
		||||
        .catch((error) => {
 | 
			
		||||
          onError(error)
 | 
			
		||||
        })
 | 
			
		||||
      .then((res) => {
 | 
			
		||||
        onSuccess(res)
 | 
			
		||||
        form.site_logo = res.data.url
 | 
			
		||||
        Message.success(res.msg)
 | 
			
		||||
      })
 | 
			
		||||
      .catch((error) => {
 | 
			
		||||
        onError(error)
 | 
			
		||||
      })
 | 
			
		||||
  })()
 | 
			
		||||
  return {
 | 
			
		||||
    abort() {
 | 
			
		||||
@@ -257,19 +257,19 @@ const handleUploadLogo = (options: RequestOption) => {
 | 
			
		||||
const handleUploadFavicon = (options: RequestOption) => {
 | 
			
		||||
  const controller = new AbortController()
 | 
			
		||||
  ;(async function requestWrap() {
 | 
			
		||||
    const {onProgress, onError, onSuccess, fileItem, name = 'file'} = options
 | 
			
		||||
    const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options
 | 
			
		||||
    onProgress(20)
 | 
			
		||||
    const formData = new FormData()
 | 
			
		||||
    formData.append(name as string, fileItem.file as Blob)
 | 
			
		||||
    uploadFile(formData)
 | 
			
		||||
        .then((res) => {
 | 
			
		||||
          onSuccess(res)
 | 
			
		||||
          form.site_favicon = res.data.url
 | 
			
		||||
          Message.success(res.msg)
 | 
			
		||||
        })
 | 
			
		||||
        .catch((error) => {
 | 
			
		||||
          onError(error)
 | 
			
		||||
        })
 | 
			
		||||
      .then((res) => {
 | 
			
		||||
        onSuccess(res)
 | 
			
		||||
        form.site_favicon = res.data.url
 | 
			
		||||
        Message.success(res.msg)
 | 
			
		||||
      })
 | 
			
		||||
      .catch((error) => {
 | 
			
		||||
        onError(error)
 | 
			
		||||
      })
 | 
			
		||||
  })()
 | 
			
		||||
  return {
 | 
			
		||||
    abort() {
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ const { form, resetForm } = useForm<DeptReq>({
 | 
			
		||||
  name: '',
 | 
			
		||||
  parentId: undefined,
 | 
			
		||||
  sort: 999,
 | 
			
		||||
  status: 1,
 | 
			
		||||
  status: 1
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 重置
 | 
			
		||||
 
 | 
			
		||||
@@ -147,7 +147,7 @@ const onDelete = async (item: DeptResp) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 导出
 | 
			
		||||
const onExport = ()=>{
 | 
			
		||||
const onExport = () => {
 | 
			
		||||
  useDownload(() => exportDept(queryForm))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,12 +55,7 @@
 | 
			
		||||
        </template>
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="组件路径" field="component" v-if="form.type === 2">
 | 
			
		||||
        <a-input
 | 
			
		||||
          v-if="form.isExternal"
 | 
			
		||||
          v-model.trim="form.component"
 | 
			
		||||
          placeholder="请输入组件路径"
 | 
			
		||||
          allow-clear
 | 
			
		||||
        />
 | 
			
		||||
        <a-input v-if="form.isExternal" v-model.trim="form.component" placeholder="请输入组件路径" allow-clear />
 | 
			
		||||
        <a-input v-else v-model.trim="form.component" placeholder="请输入组件路径" allow-clear>
 | 
			
		||||
          <template #prepend>@/views/</template>
 | 
			
		||||
          <template #append>.vue</template>
 | 
			
		||||
@@ -241,7 +236,6 @@ const save = async () => {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits<{
 | 
			
		||||
  (e: 'save-success'): void
 | 
			
		||||
}>()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <a-drawer
 | 
			
		||||
    v-model:visible="visible"
 | 
			
		||||
    title="角色详情"
 | 
			
		||||
    :width="width >= 580 ? 580 : '100%'"
 | 
			
		||||
    :footer="false"
 | 
			
		||||
  >
 | 
			
		||||
  <a-drawer v-model:visible="visible" title="角色详情" :width="width >= 580 ? 580 : '100%'" :footer="false">
 | 
			
		||||
    <a-descriptions title="基础信息" :column="2" size="large" class="general-description">
 | 
			
		||||
      <a-descriptions-item label="ID" :span="2">{{ dataDetail?.id }}</a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="名称">{{ dataDetail?.name }}</a-descriptions-item>
 | 
			
		||||
@@ -22,7 +17,13 @@
 | 
			
		||||
      <a-descriptions-item label="修改时间">{{ dataDetail?.updateTime }}</a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="描述" :span="2">{{ dataDetail?.description }}</a-descriptions-item>
 | 
			
		||||
    </a-descriptions>
 | 
			
		||||
    <a-descriptions title="功能权限" :column="2" size="large" class="general-description" style="margin-top: 20px; position: relative">
 | 
			
		||||
    <a-descriptions
 | 
			
		||||
      title="功能权限"
 | 
			
		||||
      :column="2"
 | 
			
		||||
      size="large"
 | 
			
		||||
      class="general-description"
 | 
			
		||||
      style="margin-top: 20px; position: relative"
 | 
			
		||||
    >
 | 
			
		||||
      <a-descriptions-item :span="2">
 | 
			
		||||
        <a-tree
 | 
			
		||||
          ref="menuTreeRef"
 | 
			
		||||
@@ -34,7 +35,14 @@
 | 
			
		||||
        />
 | 
			
		||||
      </a-descriptions-item>
 | 
			
		||||
    </a-descriptions>
 | 
			
		||||
    <a-descriptions v-if="dataDetail?.dataScope === 5" title="数据权限" :column="2" size="large" class="general-description" style="margin-top: 20px; position: relative">
 | 
			
		||||
    <a-descriptions
 | 
			
		||||
      v-if="dataDetail?.dataScope === 5"
 | 
			
		||||
      title="数据权限"
 | 
			
		||||
      :column="2"
 | 
			
		||||
      size="large"
 | 
			
		||||
      class="general-description"
 | 
			
		||||
      style="margin-top: 20px; position: relative"
 | 
			
		||||
    >
 | 
			
		||||
      <a-descriptions-item :span="2">
 | 
			
		||||
        <a-tree
 | 
			
		||||
          ref="deptTreeRef"
 | 
			
		||||
 
 | 
			
		||||
@@ -145,7 +145,6 @@ const RoleDetailDrawerRef = ref<InstanceType<typeof RoleDetailDrawer>>()
 | 
			
		||||
const openDetail = (item: RoleResp) => {
 | 
			
		||||
  RoleDetailDrawerRef.value?.open(item.id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -85,7 +85,7 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { getStorage, addStorage, updateStorage } from '@/apis'
 | 
			
		||||
import type { StorageReq } from './type'
 | 
			
		||||
import { Message, type FormInstance } from "@arco-design/web-vue";
 | 
			
		||||
import { Message, type FormInstance } from '@arco-design/web-vue'
 | 
			
		||||
import { useForm } from '@/hooks'
 | 
			
		||||
import { useDict } from '@/hooks/app'
 | 
			
		||||
import { useWindowSize } from '@vueuse/core'
 | 
			
		||||
 
 | 
			
		||||
@@ -100,15 +100,11 @@ const title = computed(() => (isUpdate.value ? '修改用户' : '新增用户'))
 | 
			
		||||
const formRef = ref<FormInstance>()
 | 
			
		||||
 | 
			
		||||
const rules: FormInstance['rules'] = {
 | 
			
		||||
  username: [
 | 
			
		||||
    { required: true, message: '请输入用户名' },
 | 
			
		||||
  ],
 | 
			
		||||
  nickname: [
 | 
			
		||||
    { required: true, message: '请输入昵称' },
 | 
			
		||||
  ],
 | 
			
		||||
  username: [{ required: true, message: '请输入用户名' }],
 | 
			
		||||
  nickname: [{ required: true, message: '请输入昵称' }],
 | 
			
		||||
  password: [{ required: true, message: '请输入密码' }],
 | 
			
		||||
  deptId: [{ required: true, message: '请选择所属部门' }],
 | 
			
		||||
  roleIds: [{ required: true, message: '请选择角色' }],
 | 
			
		||||
  roleIds: [{ required: true, message: '请选择角色' }]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const { form, resetForm } = useForm({
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <a-drawer
 | 
			
		||||
    v-model:visible="visible"
 | 
			
		||||
    title="用户详情"
 | 
			
		||||
    :width="width >= 580 ? 580 : '100%'"
 | 
			
		||||
    :footer="false"
 | 
			
		||||
  >
 | 
			
		||||
  <a-drawer v-model:visible="visible" title="用户详情" :width="width >= 580 ? 580 : '100%'" :footer="false">
 | 
			
		||||
    <a-descriptions :column="2" size="large" class="general-description">
 | 
			
		||||
      <a-descriptions-item label="ID" :span="2">{{ dataDetail?.id }}</a-descriptions-item>
 | 
			
		||||
      <a-descriptions-item label="用户名">{{ dataDetail?.username }}</a-descriptions-item>
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ const options: Options = {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const columns: Columns = [
 | 
			
		||||
  { label: '密码', field: 'newPassword', type: 'input-password', rules: [{ required: true, message: '请输入密码' }] },
 | 
			
		||||
  { label: '密码', field: 'newPassword', type: 'input-password', rules: [{ required: true, message: '请输入密码' }] }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
const { form, resetForm } = useForm({
 | 
			
		||||
@@ -56,7 +56,7 @@ const save = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    const isInvalid = await formRef.value?.formRef?.validate()
 | 
			
		||||
    if (isInvalid) return false
 | 
			
		||||
    await resetUserPwd({ newPassword: encryptByRsa(form.newPassword) || ''}, dataId.value)
 | 
			
		||||
    await resetUserPwd({ newPassword: encryptByRsa(form.newPassword) || '' }, dataId.value)
 | 
			
		||||
    Message.success('重置成功')
 | 
			
		||||
    emit('save-success')
 | 
			
		||||
    return true
 | 
			
		||||
 
 | 
			
		||||
@@ -6,14 +6,7 @@
 | 
			
		||||
          <a-input v-model="deptName" placeholder="请输入部门名称" allow-clear style="margin-bottom: 10px">
 | 
			
		||||
            <template #prefix><icon-search /></template>
 | 
			
		||||
          </a-input>
 | 
			
		||||
          <a-tree
 | 
			
		||||
            ref="treeRef"
 | 
			
		||||
            :data="deptList"
 | 
			
		||||
            default-expand-all
 | 
			
		||||
            show-line
 | 
			
		||||
            block-node
 | 
			
		||||
            @select="handleSelectDept"
 | 
			
		||||
          >
 | 
			
		||||
          <a-tree ref="treeRef" :data="deptList" default-expand-all show-line block-node @select="handleSelectDept">
 | 
			
		||||
          </a-tree>
 | 
			
		||||
        </a-col>
 | 
			
		||||
 | 
			
		||||
@@ -57,7 +50,12 @@
 | 
			
		||||
              </a-tooltip>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template #nickname="{ record }">
 | 
			
		||||
              <GiCellAvatar :avatar="getAvatar(record.avatar, record.gender)" :name="record.nickname" is-link @click="openDetail(record)" />
 | 
			
		||||
              <GiCellAvatar
 | 
			
		||||
                :avatar="getAvatar(record.avatar, record.gender)"
 | 
			
		||||
                :name="record.nickname"
 | 
			
		||||
                is-link
 | 
			
		||||
                @click="openDetail(record)"
 | 
			
		||||
              />
 | 
			
		||||
            </template>
 | 
			
		||||
            <template #gender="{ record }">
 | 
			
		||||
              <GiCellGender :gender="record.gender" />
 | 
			
		||||
@@ -178,7 +176,7 @@ const onDelete = (item: UserResp) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 导出
 | 
			
		||||
const onExport = ()=>{
 | 
			
		||||
const onExport = () => {
 | 
			
		||||
  useDownload(() => exportUser(queryForm))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user