提交描述
This commit is contained in:
parent
9cd49595db
commit
53b678f2ec
@ -1 +1,3 @@
|
|||||||
VITE_API_BASE_URL= ''
|
VITE_API_URL= ''
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
import { mergeConfig } from 'vite';
|
import { mergeConfig } from 'vite';
|
||||||
import eslint from 'vite-plugin-eslint';
|
import eslint from 'vite-plugin-eslint';
|
||||||
|
import * as path from 'path';
|
||||||
import baseConfig from './vite.config.base';
|
import baseConfig from './vite.config.base';
|
||||||
import * as path from "path";
|
|
||||||
|
|
||||||
export default mergeConfig(
|
export default mergeConfig(
|
||||||
{
|
{
|
||||||
@ -11,11 +11,13 @@ export default mergeConfig(
|
|||||||
fs: {
|
fs: {
|
||||||
strict: true,
|
strict: true,
|
||||||
},
|
},
|
||||||
proxy:{
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://localhost:8080',
|
target: 'http://59.110.238.182:8081',
|
||||||
|
// target: 'http://4.246.149.244:8081',
|
||||||
|
// target: 'http://localhost:5173',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
26
index.html
26
index.html
@ -1,13 +1,17 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
<head>
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="https://unpkg.byted-static.com/latest/byted/arco-config/assets/favicon.ico">
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<link rel="shortcut icon" type="image/x-icon"
|
||||||
<title>Arco Design Pro - 开箱即用的中台前端/设计解决方案</title>
|
href="https://unpkg.byted-static.com/latest/byted/arco-config/assets/favicon.ico">
|
||||||
</head>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<body>
|
<title>学院学习平台</title>
|
||||||
<div id="app"></div>
|
</head>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
|
||||||
</body>
|
<body>
|
||||||
</html>
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
195
npminstall-debug.log
Normal file
195
npminstall-debug.log
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
{
|
||||||
|
root: 'C:\\Users\\29602\\Desktop\\study\\study-fontend',
|
||||||
|
registry: 'https://registry.npmmirror.com',
|
||||||
|
pkgs: [],
|
||||||
|
production: false,
|
||||||
|
cacheStrict: false,
|
||||||
|
cacheDir: 'C:\\Users\\29602\\.npminstall_tarball',
|
||||||
|
env: {
|
||||||
|
npm_config_registry: 'https://registry.npmmirror.com',
|
||||||
|
npm_config_argv: '{"remain":[],"cooked":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\29602\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com"],"original":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\29602\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com"]}',
|
||||||
|
npm_config_user_agent: 'npminstall/7.11.1 npm/? node/v18.19.0 win32 x64',
|
||||||
|
npm_config_cache: 'C:\\Users\\29602\\.npminstall_tarball',
|
||||||
|
NODE: 'C:\\Program Files\\nodejs\\node.exe',
|
||||||
|
npm_node_execpath: 'C:\\Program Files\\nodejs\\node.exe',
|
||||||
|
npm_execpath: 'C:\\Users\\29602\\AppData\\Roaming\\npm\\node_modules\\cnpm\\node_modules\\npminstall\\bin\\install.js',
|
||||||
|
npm_config_userconfig: 'C:\\Users\\29602\\.cnpmrc',
|
||||||
|
npm_config_disturl: 'https://cdn.npmmirror.com/binaries/node',
|
||||||
|
npm_config_r: 'https://registry.npmmirror.com',
|
||||||
|
COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com',
|
||||||
|
NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
|
||||||
|
NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
|
||||||
|
PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs',
|
||||||
|
CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver',
|
||||||
|
OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver',
|
||||||
|
CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip',
|
||||||
|
ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/',
|
||||||
|
ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/',
|
||||||
|
SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass',
|
||||||
|
SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc',
|
||||||
|
NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v',
|
||||||
|
PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
|
||||||
|
PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
|
||||||
|
PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright',
|
||||||
|
SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli',
|
||||||
|
SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl',
|
||||||
|
RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2',
|
||||||
|
RE2_DOWNLOAD_SKIP_PATH: 'true',
|
||||||
|
PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma',
|
||||||
|
npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3',
|
||||||
|
npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar',
|
||||||
|
npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp',
|
||||||
|
npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips',
|
||||||
|
npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs',
|
||||||
|
npm_rootpath: 'C:\\Users\\29602\\Desktop\\study\\study-fontend',
|
||||||
|
INIT_CWD: 'C:\\Users\\29602\\Desktop\\study\\study-fontend'
|
||||||
|
},
|
||||||
|
binaryMirrors: {
|
||||||
|
ENVS: {
|
||||||
|
COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com',
|
||||||
|
NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
|
||||||
|
NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
|
||||||
|
PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs',
|
||||||
|
CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver',
|
||||||
|
OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver',
|
||||||
|
CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip',
|
||||||
|
ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/',
|
||||||
|
ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/',
|
||||||
|
SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass',
|
||||||
|
SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc',
|
||||||
|
NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v',
|
||||||
|
PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
|
||||||
|
PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
|
||||||
|
PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright',
|
||||||
|
SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli',
|
||||||
|
SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl',
|
||||||
|
RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2',
|
||||||
|
RE2_DOWNLOAD_SKIP_PATH: 'true',
|
||||||
|
PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma',
|
||||||
|
npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3',
|
||||||
|
npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar',
|
||||||
|
npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp',
|
||||||
|
npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips',
|
||||||
|
npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs'
|
||||||
|
},
|
||||||
|
'@ali/s2': { host: 'https://cdn.npmmirror.com/binaries/looksgood-s2' },
|
||||||
|
sharp: { replaceHostFiles: [Array], replaceHostMap: [Object] },
|
||||||
|
'@tensorflow/tfjs-node': {
|
||||||
|
replaceHostFiles: [Array],
|
||||||
|
replaceHostRegExpMap: [Object],
|
||||||
|
replaceHostMap: [Object]
|
||||||
|
},
|
||||||
|
cypress: {
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/cypress',
|
||||||
|
newPlatforms: [Object]
|
||||||
|
},
|
||||||
|
'utf-8-validate': {
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/utf-8-validate/v{version}'
|
||||||
|
},
|
||||||
|
xprofiler: {
|
||||||
|
remote_path: './xprofiler/v{version}/',
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries'
|
||||||
|
},
|
||||||
|
leveldown: { host: 'https://cdn.npmmirror.com/binaries/leveldown/v{version}' },
|
||||||
|
couchbase: { host: 'https://cdn.npmmirror.com/binaries/couchbase/v{version}' },
|
||||||
|
gl: { host: 'https://cdn.npmmirror.com/binaries/gl/v{version}' },
|
||||||
|
sqlite3: {
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/sqlite3',
|
||||||
|
remote_path: 'v{version}'
|
||||||
|
},
|
||||||
|
'@journeyapps/sqlcipher': { host: 'https://cdn.npmmirror.com/binaries' },
|
||||||
|
grpc: {
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries',
|
||||||
|
remote_path: '{name}/v{version}'
|
||||||
|
},
|
||||||
|
'grpc-tools': { host: 'https://cdn.npmmirror.com/binaries' },
|
||||||
|
wrtc: {
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries',
|
||||||
|
remote_path: '{name}/v{version}'
|
||||||
|
},
|
||||||
|
fsevents: { host: 'https://cdn.npmmirror.com/binaries/fsevents' },
|
||||||
|
nodejieba: { host: 'https://cdn.npmmirror.com/binaries/nodejieba' },
|
||||||
|
canvas: { host: 'https://cdn.npmmirror.com/binaries/canvas' },
|
||||||
|
'skia-canvas': { host: 'https://cdn.npmmirror.com/binaries/skia-canvas' },
|
||||||
|
'flow-bin': {
|
||||||
|
replaceHost: 'https://github.com/facebook/flow/releases/download/v',
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/flow/v'
|
||||||
|
},
|
||||||
|
'jpegtran-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/jpegtran-bin'
|
||||||
|
},
|
||||||
|
'cwebp-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/cwebp-bin'
|
||||||
|
},
|
||||||
|
'zopflipng-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/zopflipng-bin'
|
||||||
|
},
|
||||||
|
'optipng-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/optipng-bin'
|
||||||
|
},
|
||||||
|
mozjpeg: {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/mozjpeg-bin'
|
||||||
|
},
|
||||||
|
gifsicle: {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/gifsicle-bin'
|
||||||
|
},
|
||||||
|
'pngquant-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/pngquant-bin',
|
||||||
|
replaceHostMap: [Object]
|
||||||
|
},
|
||||||
|
'pngcrush-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/pngcrush-bin'
|
||||||
|
},
|
||||||
|
'jpeg-recompress-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/jpeg-recompress-bin'
|
||||||
|
},
|
||||||
|
'advpng-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/advpng-bin'
|
||||||
|
},
|
||||||
|
'pngout-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/pngout-bin'
|
||||||
|
},
|
||||||
|
'jpegoptim-bin': {
|
||||||
|
replaceHost: [Array],
|
||||||
|
host: 'https://cdn.npmmirror.com/binaries/jpegoptim-bin'
|
||||||
|
},
|
||||||
|
argon2: { host: 'https://cdn.npmmirror.com/binaries/argon2' },
|
||||||
|
'ali-zeromq': { host: 'https://cdn.npmmirror.com/binaries/ali-zeromq' },
|
||||||
|
'ali-usb_ctl': { host: 'https://cdn.npmmirror.com/binaries/ali-usb_ctl' },
|
||||||
|
'gdal-async': { host: 'https://cdn.npmmirror.com/binaries/node-gdal-async' },
|
||||||
|
'libpg-query': { host: 'https://cdn.npmmirror.com/binaries' }
|
||||||
|
},
|
||||||
|
forbiddenLicenses: null,
|
||||||
|
flatten: false,
|
||||||
|
proxy: undefined,
|
||||||
|
prune: false,
|
||||||
|
disableFallbackStore: false,
|
||||||
|
workspacesMap: Map(0) {},
|
||||||
|
enableWorkspace: false,
|
||||||
|
workspaceRoot: 'C:\\Users\\29602\\Desktop\\study\\study-fontend',
|
||||||
|
isWorkspaceRoot: true,
|
||||||
|
isWorkspacePackage: false,
|
||||||
|
offline: false,
|
||||||
|
strictSSL: true,
|
||||||
|
ignoreScripts: false,
|
||||||
|
foregroundScripts: false,
|
||||||
|
ignoreOptionalDependencies: false,
|
||||||
|
detail: false,
|
||||||
|
forceLinkLatest: false,
|
||||||
|
trace: false,
|
||||||
|
engineStrict: false,
|
||||||
|
registryOnly: false,
|
||||||
|
client: false,
|
||||||
|
autoFixVersion: [Function: autoFixVersion]
|
||||||
|
}
|
@ -12,7 +12,11 @@
|
|||||||
"preview": "npm run build && vite preview --host",
|
"preview": "npm run build && vite preview --host",
|
||||||
"type:check": "vue-tsc --noEmit --skipLibCheck",
|
"type:check": "vue-tsc --noEmit --skipLibCheck",
|
||||||
"lint-staged": "npx lint-staged",
|
"lint-staged": "npx lint-staged",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install",
|
||||||
|
|
||||||
|
"start": "npm run dev"
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,ts,jsx,tsx}": [
|
"*.{js,ts,jsx,tsx}": [
|
||||||
|
@ -21,6 +21,14 @@ axios.interceptors.request.use(
|
|||||||
// this example using the JWT token
|
// this example using the JWT token
|
||||||
// Authorization is a custom headers key
|
// Authorization is a custom headers key
|
||||||
// please modify it according to the actual situation
|
// please modify it according to the actual situation
|
||||||
|
const userStore = useUserStore();
|
||||||
|
// console.log('config', config);
|
||||||
|
// if (config.url === '/api/erst/user/me') {
|
||||||
|
// userStore.headerName = 'zsc';
|
||||||
|
// userStore.tokenDate = '123';
|
||||||
|
config.headers['X-CSRF-TOKEN'] = userStore.tokenDate;
|
||||||
|
// }
|
||||||
|
|
||||||
const token = getToken();
|
const token = getToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
if (!config.headers) {
|
if (!config.headers) {
|
||||||
@ -28,6 +36,7 @@ axios.interceptors.request.use(
|
|||||||
}
|
}
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
@ -70,7 +79,7 @@ axios.interceptors.response.use(
|
|||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
const { response } = error;
|
const { response } = error;
|
||||||
console.log(response);
|
console.log('error', error);
|
||||||
if (
|
if (
|
||||||
[50008, 50012, 50014].includes(response.data.code) &&
|
[50008, 50012, 50014].includes(response.data.code) &&
|
||||||
response.config.url !== '/api/user/info'
|
response.config.url !== '/api/user/info'
|
||||||
|
@ -8,6 +8,17 @@ export interface RoleCreateRecord {
|
|||||||
permissionIds: (number | undefined)[];
|
permissionIds: (number | undefined)[];
|
||||||
remark: string;
|
remark: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ListRecord {
|
||||||
|
username: string;
|
||||||
|
phone: string;
|
||||||
|
email: string;
|
||||||
|
enable: string;
|
||||||
|
nickname: string;
|
||||||
|
avater: string;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RoleRecord extends RoleCreateRecord {
|
export interface RoleRecord extends RoleCreateRecord {
|
||||||
permissions?: [];
|
permissions?: [];
|
||||||
}
|
}
|
||||||
@ -16,24 +27,35 @@ export interface RoleListRecord extends RoleRecord {
|
|||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function create(data: RoleCreateRecord) {
|
export function create(data: RoleCreateRecord) {
|
||||||
return axios.post(`/api/role`, data);
|
return axios.post(`/api/role`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新用户
|
||||||
export function update(data: RoleRecord) {
|
export function update(data: RoleRecord) {
|
||||||
return axios.patch(`/api/role/${data.id}`, data);
|
return axios.patch(`/api/rest/user/${data.id}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getDetail(id: number) {
|
export function getDetail(id: number) {
|
||||||
return axios.get<RoleRecord>(`/api/role/${id}`);
|
return axios.get<RoleRecord>(`/api/role/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function remove(id: number) {
|
// 删除用户
|
||||||
return axios.delete(`/api/role/${id}`);
|
export function remove(id: string) {
|
||||||
|
return axios.delete(`/api/rest/role/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 模糊查询用户列表
|
||||||
export function queryRoles(params?: ListParams<Partial<RoleRecord>>) {
|
export function queryRoles(params?: ListParams<Partial<RoleRecord>>) {
|
||||||
return queryList<RoleRecord>(`/api/role`, params);
|
return queryList<RoleRecord>(`/api/rest/user/query`, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加用户
|
||||||
|
export function addUser(params: ListRecord) {
|
||||||
|
return axios.post('/api/rest/user/register', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否启用
|
||||||
|
export function enabled(id: string) {
|
||||||
|
return axios.patch(`/api/rest/user/${id}/toggle`);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ export interface LoginRes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PasswordReSetModel {
|
export interface PasswordReSetModel {
|
||||||
newPassword: string;
|
oldPassword: string;
|
||||||
|
password: string;
|
||||||
confirmPassword: string;
|
confirmPassword: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,16 +74,30 @@ export interface UserListRes {
|
|||||||
pageable: Pageable;
|
pageable: Pageable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function login(data: LoginData) {
|
// 获取令牌
|
||||||
return axios.post<LoginRes>('/api/user/login', data);
|
export function me() {
|
||||||
|
return axios.get('/api/rest/user/me');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户登录
|
||||||
|
export function login(data: LoginData, headerName: string, token: string) {
|
||||||
|
return axios({
|
||||||
|
url: '/api/rest/user/login',
|
||||||
|
data,
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
[headerName]: token,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
return axios.post<LoginRes>('/api/user/logout');
|
return axios.post<LoginRes>('/api/rest/user/logout');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新密码
|
||||||
export function resetPassword(data: PasswordReSetModel) {
|
export function resetPassword(data: PasswordReSetModel) {
|
||||||
return axios.patch('/api/user/self/update-password', data);
|
return axios.patch('/api/rest/user/self/update-password', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function create(data: CreateRecord) {
|
export function create(data: CreateRecord) {
|
||||||
@ -94,15 +109,16 @@ export function update(data: UserRecord) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function selfUpdate(data: UserState) {
|
export function selfUpdate(data: UserState) {
|
||||||
return axios.patch<Res>(`/api/user/self`, data);
|
return axios.patch<Res>(`/api/rest/user/self`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function switchRole(roleId: number) {
|
export function switchRole(roleId: number) {
|
||||||
return axios.patch<UserState>(`/api/user/self/switch-role/${roleId}`);
|
return axios.patch<UserState>(`/api/user/self/switch-role/${roleId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
export function getUserInfo() {
|
export function getUserInfo() {
|
||||||
return axios.get<UserState>('/api/user/info');
|
return axios.get<UserState>('/api/rest/user/self');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserDetail(id: number) {
|
export function getUserDetail(id: number) {
|
||||||
@ -124,4 +140,4 @@ export function queryUserList(params: UserParams) {
|
|||||||
return qs.stringify(obj);
|
return qs.stringify(obj);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
:style="{ margin: 0, fontSize: '18px' }"
|
:style="{ margin: 0, fontSize: '18px' }"
|
||||||
:heading="5"
|
:heading="5"
|
||||||
>
|
>
|
||||||
Arco Pro
|
中山学院
|
||||||
</a-typography-title>
|
</a-typography-title>
|
||||||
<icon-menu-fold
|
<icon-menu-fold
|
||||||
v-if="!topMenu && appStore.device === 'mobile'"
|
v-if="!topMenu && appStore.device === 'mobile'"
|
||||||
@ -23,15 +23,15 @@
|
|||||||
<Menu v-if="topMenu" />
|
<Menu v-if="topMenu" />
|
||||||
</div>
|
</div>
|
||||||
<ul class="right-side">
|
<ul class="right-side">
|
||||||
<!-- <li>-->
|
<!-- <li>-->
|
||||||
<!-- <a-tooltip :content="$t('settings.search')">-->
|
<!-- <a-tooltip :content="$t('settings.search')">-->
|
||||||
<!-- <a-button class="nav-btn" type="outline" :shape="'circle'">-->
|
<!-- <a-button class="nav-btn" type="outline" :shape="'circle'">-->
|
||||||
<!-- <template #icon>-->
|
<!-- <template #icon>-->
|
||||||
<!-- <icon-search />-->
|
<!-- <icon-search />-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
<!-- </a-button>-->
|
<!-- </a-button>-->
|
||||||
<!-- </a-tooltip>-->
|
<!-- </a-tooltip>-->
|
||||||
<!-- </li>-->
|
<!-- </li>-->
|
||||||
<li>
|
<li>
|
||||||
<a-tooltip :content="$t('settings.language')">
|
<a-tooltip :content="$t('settings.language')">
|
||||||
<a-button
|
<a-button
|
||||||
@ -144,16 +144,7 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a-tooltip content="切换用户角色">
|
|
||||||
<a-select
|
|
||||||
v-model="defaultRole"
|
|
||||||
:style="{ width: '140px' }"
|
|
||||||
:options="roleOptions as SelectOptionData[]"
|
|
||||||
@change="switchRoles"
|
|
||||||
/>
|
|
||||||
</a-tooltip>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<a-dropdown trigger="click">
|
<a-dropdown trigger="click">
|
||||||
<a-avatar
|
<a-avatar
|
||||||
@ -163,14 +154,14 @@
|
|||||||
<img alt="avatar" :src="avatar" />
|
<img alt="avatar" :src="avatar" />
|
||||||
</a-avatar>
|
</a-avatar>
|
||||||
<template #content>
|
<template #content>
|
||||||
<!-- <a-doption>-->
|
<!-- <a-doption>-->
|
||||||
<!-- <a-space @click="switchRoles">-->
|
<!-- <a-space @click="switchRoles">-->
|
||||||
<!-- <icon-tag />-->
|
<!-- <icon-tag />-->
|
||||||
<!-- <span>-->
|
<!-- <span>-->
|
||||||
<!-- {{ $t('messageBox.switchRoles') }}-->
|
<!-- {{ $t('messageBox.switchRoles') }}-->
|
||||||
<!-- </span>-->
|
<!-- </span>-->
|
||||||
<!-- </a-space>-->
|
<!-- </a-space>-->
|
||||||
<!-- </a-doption>-->
|
<!-- </a-doption>-->
|
||||||
<a-doption>
|
<a-doption>
|
||||||
<a-space @click="$router.push({ name: 'Info' })">
|
<a-space @click="$router.push({ name: 'Info' })">
|
||||||
<icon-user />
|
<icon-user />
|
||||||
@ -203,144 +194,144 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, inject } from 'vue';
|
import { computed, ref, inject } from 'vue';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { useDark, useToggle, useFullscreen } from '@vueuse/core';
|
import { useDark, useToggle, useFullscreen } from '@vueuse/core';
|
||||||
import { useAppStore, useUserStore } from '@/store';
|
import { useAppStore, useUserStore } from '@/store';
|
||||||
import { LOCALE_OPTIONS } from '@/locale';
|
import { LOCALE_OPTIONS } from '@/locale';
|
||||||
import useLocale from '@/hooks/locale';
|
import useLocale from '@/hooks/locale';
|
||||||
import useUser from '@/hooks/user';
|
import useUser from '@/hooks/user';
|
||||||
import Menu from '@/components/menu/index.vue';
|
import Menu from '@/components/menu/index.vue';
|
||||||
import userIcon from '@/assets/images/user-circle.png';
|
import userIcon from '@/assets/images/user-circle.png';
|
||||||
import { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
|
import { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
|
||||||
import MessageBox from '../message-box/index.vue';
|
import MessageBox from '../message-box/index.vue';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { logout } = useUser();
|
const { logout } = useUser();
|
||||||
const { changeLocale, currentLocale } = useLocale();
|
const { changeLocale, currentLocale } = useLocale();
|
||||||
const { isFullscreen, toggle: toggleFullScreen } = useFullscreen();
|
const { isFullscreen, toggle: toggleFullScreen } = useFullscreen();
|
||||||
const locales = [...LOCALE_OPTIONS];
|
const locales = [...LOCALE_OPTIONS];
|
||||||
const avatar = computed(() => {
|
const avatar = computed(() => {
|
||||||
return userStore.avatar ? userStore.avatar : userIcon;
|
return userStore.avatar ? userStore.avatar : userIcon;
|
||||||
|
});
|
||||||
|
const theme = computed(() => {
|
||||||
|
return appStore.theme;
|
||||||
|
});
|
||||||
|
const topMenu = computed(() => appStore.topMenu && appStore.menu);
|
||||||
|
const isDark = useDark({
|
||||||
|
selector: 'body',
|
||||||
|
attribute: 'arco-theme',
|
||||||
|
valueDark: 'dark',
|
||||||
|
valueLight: 'light',
|
||||||
|
storageKey: 'arco-theme',
|
||||||
|
onChanged(dark: boolean) {
|
||||||
|
// overridden default behavior
|
||||||
|
appStore.toggleTheme(dark);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const toggleTheme = useToggle(isDark);
|
||||||
|
const handleToggleTheme = () => {
|
||||||
|
toggleTheme();
|
||||||
|
};
|
||||||
|
const setVisible = () => {
|
||||||
|
appStore.updateSettings({ globalSettings: true });
|
||||||
|
};
|
||||||
|
const refBtn = ref();
|
||||||
|
const triggerBtn = ref();
|
||||||
|
const defaultRole = ref(userStore.role?.id);
|
||||||
|
const roleOptions = computed(() => {
|
||||||
|
return userStore.roles?.map((role) => {
|
||||||
|
return {
|
||||||
|
value: role.id,
|
||||||
|
label: role.name,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
const theme = computed(() => {
|
});
|
||||||
return appStore.theme;
|
const setPopoverVisible = () => {
|
||||||
|
const event = new MouseEvent('click', {
|
||||||
|
view: window,
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
});
|
});
|
||||||
const topMenu = computed(() => appStore.topMenu && appStore.menu);
|
refBtn.value.dispatchEvent(event);
|
||||||
const isDark = useDark({
|
};
|
||||||
selector: 'body',
|
const handleLogout = () => {
|
||||||
attribute: 'arco-theme',
|
logout();
|
||||||
valueDark: 'dark',
|
};
|
||||||
valueLight: 'light',
|
const setDropDownVisible = () => {
|
||||||
storageKey: 'arco-theme',
|
const event = new MouseEvent('click', {
|
||||||
onChanged(dark: boolean) {
|
view: window,
|
||||||
// overridden default behavior
|
bubbles: true,
|
||||||
appStore.toggleTheme(dark);
|
cancelable: true,
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const toggleTheme = useToggle(isDark);
|
triggerBtn.value.dispatchEvent(event);
|
||||||
const handleToggleTheme = () => {
|
};
|
||||||
toggleTheme();
|
const switchRoles = async (value: number) => {
|
||||||
};
|
// 切换角色
|
||||||
const setVisible = () => {
|
await userStore.switchRoles(value);
|
||||||
appStore.updateSettings({ globalSettings: true });
|
window.location.reload();
|
||||||
};
|
// Message.success(res as string);
|
||||||
const refBtn = ref();
|
};
|
||||||
const triggerBtn = ref();
|
const toggleDrawerMenu = inject('toggleDrawerMenu') as () => void;
|
||||||
const defaultRole = ref(userStore.role?.id);
|
|
||||||
const roleOptions = computed(() => {
|
|
||||||
return userStore.roles?.map((role) => {
|
|
||||||
return {
|
|
||||||
value: role.id,
|
|
||||||
label: role.name,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const setPopoverVisible = () => {
|
|
||||||
const event = new MouseEvent('click', {
|
|
||||||
view: window,
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
});
|
|
||||||
refBtn.value.dispatchEvent(event);
|
|
||||||
};
|
|
||||||
const handleLogout = () => {
|
|
||||||
logout();
|
|
||||||
};
|
|
||||||
const setDropDownVisible = () => {
|
|
||||||
const event = new MouseEvent('click', {
|
|
||||||
view: window,
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
});
|
|
||||||
triggerBtn.value.dispatchEvent(event);
|
|
||||||
};
|
|
||||||
const switchRoles = async (value: number) => {
|
|
||||||
// 切换角色
|
|
||||||
await userStore.switchRoles(value);
|
|
||||||
window.location.reload();
|
|
||||||
// Message.success(res as string);
|
|
||||||
};
|
|
||||||
const toggleDrawerMenu = inject('toggleDrawerMenu') as () => void;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.navbar {
|
.navbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: var(--color-bg-2);
|
background-color: var(--color-bg-2);
|
||||||
border-bottom: 1px solid var(--color-border);
|
border-bottom: 1px solid var(--color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-side {
|
.left-side {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-side {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-side {
|
||||||
|
display: flex;
|
||||||
|
padding-right: 20px;
|
||||||
|
list-style: none;
|
||||||
|
:deep(.locale-select) {
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
li {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: 20px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center-side {
|
a {
|
||||||
flex: 1;
|
color: var(--color-text-1);
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
.nav-btn {
|
||||||
.right-side {
|
border-color: rgb(var(--gray-2));
|
||||||
display: flex;
|
color: rgb(var(--gray-8));
|
||||||
padding-right: 20px;
|
font-size: 16px;
|
||||||
list-style: none;
|
|
||||||
:deep(.locale-select) {
|
|
||||||
border-radius: 20px;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--color-text-1);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.nav-btn {
|
|
||||||
border-color: rgb(var(--gray-2));
|
|
||||||
color: rgb(var(--gray-8));
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.trigger-btn,
|
|
||||||
.ref-btn {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 14px;
|
|
||||||
}
|
|
||||||
.trigger-btn {
|
|
||||||
margin-left: 14px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.trigger-btn,
|
||||||
|
.ref-btn {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 14px;
|
||||||
|
}
|
||||||
|
.trigger-btn {
|
||||||
|
margin-left: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.message-popover {
|
.message-popover {
|
||||||
.arco-popover-content {
|
.arco-popover-content {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -28,6 +28,7 @@ import localeUserSetting from '@/views/user/setting/locale/en-US';
|
|||||||
|
|
||||||
import systemUser from '@/views/system/user/locale/en-US';
|
import systemUser from '@/views/system/user/locale/en-US';
|
||||||
|
|
||||||
|
import localRole from '@/views/character/manage/locale/zh-CN';
|
||||||
import localeSettings from './en-US/settings';
|
import localeSettings from './en-US/settings';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -45,6 +46,7 @@ export default {
|
|||||||
'menu.arcoWebsite': 'Arco Design',
|
'menu.arcoWebsite': 'Arco Design',
|
||||||
'menu.faq': 'FAQ',
|
'menu.faq': 'FAQ',
|
||||||
'menu.system': 'System',
|
'menu.system': 'System',
|
||||||
|
'menu.role': 'Role',
|
||||||
'navbar.docs': 'Docs',
|
'navbar.docs': 'Docs',
|
||||||
'navbar.action.locale': 'Switch to English',
|
'navbar.action.locale': 'Switch to English',
|
||||||
...localeSettings,
|
...localeSettings,
|
||||||
@ -67,5 +69,6 @@ export default {
|
|||||||
...locale500,
|
...locale500,
|
||||||
...localeUserInfo,
|
...localeUserInfo,
|
||||||
...localeUserSetting,
|
...localeUserSetting,
|
||||||
|
...localRole,
|
||||||
...systemUser,
|
...systemUser,
|
||||||
};
|
};
|
||||||
|
@ -28,6 +28,7 @@ import localeUserSetting from '@/views/user/setting/locale/zh-CN';
|
|||||||
|
|
||||||
import systemUser from '@/views/system/user/locale/zh-CN';
|
import systemUser from '@/views/system/user/locale/zh-CN';
|
||||||
|
|
||||||
|
import localRole from '@/views/character/manage/locale/zh-CN';
|
||||||
import localeSettings from './zh-CN/settings';
|
import localeSettings from './zh-CN/settings';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -45,6 +46,7 @@ export default {
|
|||||||
'menu.arcoWebsite': 'Arco Design',
|
'menu.arcoWebsite': 'Arco Design',
|
||||||
'menu.faq': '常见问题',
|
'menu.faq': '常见问题',
|
||||||
'menu.system': '系统管理',
|
'menu.system': '系统管理',
|
||||||
|
'menu.role': '角色中心',
|
||||||
'navbar.docs': '文档中心',
|
'navbar.docs': '文档中心',
|
||||||
'navbar.action.locale': '切换为中文',
|
'navbar.action.locale': '切换为中文',
|
||||||
...localeSettings,
|
...localeSettings,
|
||||||
@ -67,6 +69,7 @@ export default {
|
|||||||
...locale500,
|
...locale500,
|
||||||
...localeUserInfo,
|
...localeUserInfo,
|
||||||
...localeUserSetting,
|
...localeUserSetting,
|
||||||
|
...localRole,
|
||||||
|
|
||||||
...systemUser,
|
...systemUser,
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@ setupMock({
|
|||||||
// Mock.XHR.prototype.withCredentials = true;
|
// Mock.XHR.prototype.withCredentials = true;
|
||||||
|
|
||||||
// 用户信息
|
// 用户信息
|
||||||
Mock.mock(new RegExp('/api/user/info'), () => {
|
Mock.mock(new RegExp('/api/rest/user/info'), () => {
|
||||||
if (isLogin()) {
|
if (isLogin()) {
|
||||||
const role = window.localStorage.getItem('userRole') || 'admin';
|
const role = window.localStorage.getItem('userRole') || 'admin';
|
||||||
return successResponseWrap({
|
return successResponseWrap({
|
||||||
@ -39,7 +39,7 @@ setupMock({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 登录
|
// 登录
|
||||||
Mock.mock(new RegExp('/api/user/login'), (params: MockParams) => {
|
Mock.mock(new RegExp('/api/rest/user/login'), (params: MockParams) => {
|
||||||
const { username, password } = JSON.parse(params.body);
|
const { username, password } = JSON.parse(params.body);
|
||||||
if (!username) {
|
if (!username) {
|
||||||
return failResponseWrap(null, '用户名不能为空', 50000);
|
return failResponseWrap(null, '用户名不能为空', 50000);
|
||||||
|
@ -23,6 +23,7 @@ const router = createRouter({
|
|||||||
requiresAuth: false,
|
requiresAuth: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
...appRoutes,
|
...appRoutes,
|
||||||
REDIRECT_MAIN,
|
REDIRECT_MAIN,
|
||||||
NOT_FOUND_ROUTE,
|
NOT_FOUND_ROUTE,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import type { RouteRecordNormalized } from 'vue-router';
|
import type { RouteRecordNormalized } from 'vue-router';
|
||||||
|
|
||||||
const modules = import.meta.glob('./modules/*.ts', { eager: true });
|
const modules = import.meta.glob('./modules/*.ts', { eager: true });
|
||||||
|
|
||||||
const externalModules = import.meta.glob('./externalModules/*.ts', {
|
const externalModules = import.meta.glob('./externalModules/*.ts', {
|
||||||
eager: true,
|
eager: true,
|
||||||
});
|
});
|
||||||
|
28
src/router/routes/modules/character.ts
Normal file
28
src/router/routes/modules/character.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { DEFAULT_LAYOUT } from '../base';
|
||||||
|
import { AppRouteRecordRaw } from '../types';
|
||||||
|
|
||||||
|
const CHARACTER: AppRouteRecordRaw = {
|
||||||
|
path: '/character',
|
||||||
|
name: 'character',
|
||||||
|
component: DEFAULT_LAYOUT,
|
||||||
|
meta: {
|
||||||
|
locale: 'menu.role',
|
||||||
|
icon: 'icon-computer',
|
||||||
|
requiresAuth: true,
|
||||||
|
order: 2,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'manage',
|
||||||
|
name: 'Manage',
|
||||||
|
component: () => import('@/views/character/manage/index.vue'),
|
||||||
|
meta: {
|
||||||
|
locale: 'menu.role.manage',
|
||||||
|
requiresAuth: true,
|
||||||
|
permissions: ['*'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CHARACTER;
|
@ -8,8 +8,8 @@ const DASHBOARD: AppRouteRecordRaw = {
|
|||||||
meta: {
|
meta: {
|
||||||
locale: 'menu.dashboard',
|
locale: 'menu.dashboard',
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
icon: 'icon-dashboard',
|
icon: 'icon-dashboard', // 设置图标
|
||||||
order: 0,
|
order: 0, // 排序路由菜单项。如果设置该值,值越高,越靠前
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -24,13 +24,13 @@ const DASHBOARD: AppRouteRecordRaw = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: 'monitor',
|
path: 'monitor',// 一级路径
|
||||||
name: 'Monitor',
|
name: 'Monitor',// 路由名称
|
||||||
component: () => import('@/views/dashboard/monitor/index.vue'),
|
component: () => import('@/views/dashboard/monitor/index.vue'),// 要跳转的视图,这里要跳转到页面的基本布局
|
||||||
meta: {
|
meta: {
|
||||||
locale: 'menu.dashboard.monitor',
|
locale: 'menu.dashboard.monitor',// 菜单名字
|
||||||
requiresAuth: true,
|
requiresAuth: true,// 需要登录鉴权
|
||||||
permissions: ['admin'],
|
permissions: ['admin'],// 只允许管理员用户访问
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -3,9 +3,10 @@ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
|||||||
import useAppStore from './modules/app';
|
import useAppStore from './modules/app';
|
||||||
import useUserStore from './modules/user';
|
import useUserStore from './modules/user';
|
||||||
import useTabBarStore from './modules/tab-bar';
|
import useTabBarStore from './modules/tab-bar';
|
||||||
|
import useRoleStore from './modules/role';
|
||||||
|
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
pinia.use(piniaPluginPersistedstate);
|
pinia.use(piniaPluginPersistedstate);
|
||||||
|
|
||||||
export { useAppStore, useUserStore, useTabBarStore };
|
export { useAppStore, useUserStore, useTabBarStore, useRoleStore };
|
||||||
export default pinia;
|
export default pinia;
|
||||||
|
54
src/store/modules/role/index.ts
Normal file
54
src/store/modules/role/index.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import {
|
||||||
|
queryRoles,
|
||||||
|
ListRecord,
|
||||||
|
addUser,
|
||||||
|
remove,
|
||||||
|
update,
|
||||||
|
enabled,
|
||||||
|
} from '@/api/role';
|
||||||
|
import { RoleState } from './type';
|
||||||
|
|
||||||
|
const useRoleStore = defineStore('role', {
|
||||||
|
state: (): RoleState => ({
|
||||||
|
current: undefined,
|
||||||
|
pageSize: undefined,
|
||||||
|
username: undefined,
|
||||||
|
phone: undefined,
|
||||||
|
email: undefined,
|
||||||
|
enable: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
avater: undefined,
|
||||||
|
address: undefined,
|
||||||
|
}),
|
||||||
|
|
||||||
|
getters: {
|
||||||
|
roleInfo(state: RoleState): RoleState {
|
||||||
|
return { ...state };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async getUserInfo(params: any) {
|
||||||
|
const res = await queryRoles(params);
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
|
async addUser(params: any) {
|
||||||
|
return addUser(params);
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteUser(id: string) {
|
||||||
|
return remove(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
async updateUser(data: any) {
|
||||||
|
return update(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
async enabledStatus(id: string) {
|
||||||
|
return enabled(id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useRoleStore;
|
14
src/store/modules/role/type.ts
Normal file
14
src/store/modules/role/type.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { RoleRecord } from '@/api/role';
|
||||||
|
|
||||||
|
export type RoleType = '' | '*' | 'admin' | 'user' | string[];
|
||||||
|
export interface RoleState {
|
||||||
|
current?: string;
|
||||||
|
pageSize?: string;
|
||||||
|
username?: string;
|
||||||
|
phone?: string;
|
||||||
|
email?: string;
|
||||||
|
enable?: string;
|
||||||
|
nickname?: string;
|
||||||
|
avater?: string;
|
||||||
|
address?: string;
|
||||||
|
}
|
@ -5,6 +5,7 @@ import {
|
|||||||
switchRole,
|
switchRole,
|
||||||
getUserInfo,
|
getUserInfo,
|
||||||
LoginData,
|
LoginData,
|
||||||
|
me,
|
||||||
} from '@/api/user';
|
} from '@/api/user';
|
||||||
import { setToken, clearToken } from '@/utils/auth';
|
import { setToken, clearToken } from '@/utils/auth';
|
||||||
import { removeRouteListener } from '@/utils/route-listener';
|
import { removeRouteListener } from '@/utils/route-listener';
|
||||||
@ -14,16 +15,19 @@ import useAppStore from '../app';
|
|||||||
const useUserStore = defineStore('user', {
|
const useUserStore = defineStore('user', {
|
||||||
state: (): UserState => ({
|
state: (): UserState => ({
|
||||||
username: undefined,
|
username: undefined,
|
||||||
name: undefined,
|
nickName: undefined,
|
||||||
avatar: undefined,
|
avatar: undefined,
|
||||||
email: undefined,
|
email: undefined,
|
||||||
phone: undefined,
|
phone: undefined,
|
||||||
|
address: undefined,
|
||||||
createAt: undefined,
|
createAt: undefined,
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
id: undefined,
|
id: undefined,
|
||||||
role: undefined,
|
role: undefined,
|
||||||
roles: undefined,
|
roles: undefined,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
|
headerName: '',
|
||||||
|
tokenDate: '',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
@ -60,12 +64,20 @@ const useUserStore = defineStore('user', {
|
|||||||
this.setInfo(res.data);
|
this.setInfo(res.data);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Get user's crsf
|
||||||
|
async me() {
|
||||||
|
const res = await me();
|
||||||
|
this.headerName = res.data.csrf.headerName;
|
||||||
|
this.tokenDate = res.data.csrf.token;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
async login(loginForm: LoginData) {
|
async login(loginForm: LoginData, headerName: string, token: string) {
|
||||||
try {
|
try {
|
||||||
const res = await userLogin(loginForm);
|
const res = await userLogin(loginForm, headerName, token);
|
||||||
// setToken(res.data.token);
|
setToken(token);
|
||||||
setToken(res.data.token);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
clearToken();
|
clearToken();
|
||||||
throw err;
|
throw err;
|
||||||
|
@ -3,14 +3,17 @@ import { RoleRecord } from '@/api/role';
|
|||||||
export type RoleType = '' | '*' | 'admin' | 'user' | string[];
|
export type RoleType = '' | '*' | 'admin' | 'user' | string[];
|
||||||
export interface UserState {
|
export interface UserState {
|
||||||
username?: string;
|
username?: string;
|
||||||
name?: string;
|
nickName?: string;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
|
address?: string;
|
||||||
createAt?: string;
|
createAt?: string;
|
||||||
remark?: string;
|
remark?: string;
|
||||||
id?: number;
|
id?: number;
|
||||||
role?: RoleRecord;
|
role?: RoleRecord;
|
||||||
roles?: RoleRecord[];
|
roles?: RoleRecord[];
|
||||||
permissions?: string[] | '' | '*' | 'admin' | 'user';
|
permissions?: string[] | '' | '*' | 'admin' | 'user';
|
||||||
|
headerName: string;
|
||||||
|
tokenDate: string;
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,8 @@ export interface PostData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Pagination {
|
export interface Pagination {
|
||||||
current: number;
|
page: number;
|
||||||
pageSize: number;
|
size: number;
|
||||||
total?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TimeRanger = [string, string];
|
export type TimeRanger = [string, string];
|
||||||
|
489
src/views/character/manage/index.vue
Normal file
489
src/views/character/manage/index.vue
Normal file
@ -0,0 +1,489 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<Breadcrumb :items="['menu.role', 'menu.role.manage']" />
|
||||||
|
|
||||||
|
<a-card class="general-card" :title="$t('menu.list.searchTable')">
|
||||||
|
<a-row>
|
||||||
|
<a-col :flex="1">
|
||||||
|
<a-form
|
||||||
|
:model="formModel"
|
||||||
|
:label-col-props="{ span: 6 }"
|
||||||
|
:wrapper-col-props="{ span: 18 }"
|
||||||
|
label-align="left"
|
||||||
|
>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="7">
|
||||||
|
<a-form-item
|
||||||
|
field="username"
|
||||||
|
:label="$t('searchTable.form.username')"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model="formModel.username"
|
||||||
|
:placeholder="$t('searchTable.form.username.placeholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="9">
|
||||||
|
<a-form-item
|
||||||
|
field="phone"
|
||||||
|
:label="$t('searchTable.form.phone')"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model="formModel.phone"
|
||||||
|
:placeholder="$t('searchTable.form.phone.placeholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="8">
|
||||||
|
<a-form-item
|
||||||
|
field="email"
|
||||||
|
:label="$t('searchTable.form.email')"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model="formModel.email"
|
||||||
|
:placeholder="$t('searchTable.form.email.placeholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<!-- <a-col :span="9">
|
||||||
|
<a-form-item field="role" :label="$t('searchTable.form.role')">
|
||||||
|
<a-select
|
||||||
|
v-model="formModel.role"
|
||||||
|
:options="roleOptions"
|
||||||
|
:placeholder="$t('searchTable.form.role.placeholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col> -->
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</a-col>
|
||||||
|
<a-divider style="height: 84px" direction="vertical" />
|
||||||
|
|
||||||
|
<!-- 更新和重置按钮 -->
|
||||||
|
<a-col :flex="'86px'" style="text-align: right">
|
||||||
|
<a-space direction="vertical" :size="18">
|
||||||
|
<a-button type="primary" @click="search">
|
||||||
|
<template #icon>
|
||||||
|
<icon-search />
|
||||||
|
</template>
|
||||||
|
{{ $t('searchTable.form.search') }}
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="reset">
|
||||||
|
<template #icon>
|
||||||
|
<icon-refresh />
|
||||||
|
</template>
|
||||||
|
{{ $t('searchTable.form.reset') }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-divider style="margin-top: 0" />
|
||||||
|
<a-row :gutter="10">
|
||||||
|
<a-col :span="9">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
@click="handleClick"
|
||||||
|
style="margin-right: 16px"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
{{ $t('searchTable.operation.create') }}
|
||||||
|
</a-button>
|
||||||
|
|
||||||
|
<a-button type="primary" status="danger" @click="handleDelete">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close />
|
||||||
|
</template>
|
||||||
|
{{ $t('searchTable.operation.delete') }}
|
||||||
|
</a-button>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-divider style="margin-top: 16px" />
|
||||||
|
<a-table
|
||||||
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
|
:pagination="false"
|
||||||
|
:columns="(cloneColumns as TableColumnData[])"
|
||||||
|
:data="renderData"
|
||||||
|
:bordered="false"
|
||||||
|
:size="size"
|
||||||
|
:row-selection="true"
|
||||||
|
@select="selectRow"
|
||||||
|
>
|
||||||
|
<template #index="{ rowIndex }">
|
||||||
|
{{ rowIndex + 1 + (pagination.page - 1) * pagination.size }}
|
||||||
|
</template>
|
||||||
|
<template #enabled="{ record }">
|
||||||
|
<a-switch
|
||||||
|
:model-value="record.enabled"
|
||||||
|
:checked-value="true"
|
||||||
|
:unchecked-value="false"
|
||||||
|
@change="enabledStatus(record)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #operations="{ record }">
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
@click="handleClick(record, 'modify')"
|
||||||
|
>
|
||||||
|
{{ $t('searchTable.columns.operations.detail') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<a-space direction="vertical" size="large" style="margin-top: 16px">
|
||||||
|
<a-pagination
|
||||||
|
show-total
|
||||||
|
:current="pagination.page"
|
||||||
|
@change="onPageChange"
|
||||||
|
:page-size="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
/>
|
||||||
|
</a-space>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="visible"
|
||||||
|
:title="dialogTitle"
|
||||||
|
:mask-closable="false"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:before-ok="handleBeforeOk"
|
||||||
|
>
|
||||||
|
<a-form :model="formDate">
|
||||||
|
<a-form-item field="username" :label="$t('add.user.info.username')">
|
||||||
|
<a-input
|
||||||
|
v-model="formDate.username"
|
||||||
|
:placeholder="$t('add.user.info.username.placeholder')"
|
||||||
|
:required="required"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '用户名不能为空',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="password" :label="$t('add.user.info.password')">
|
||||||
|
<a-input-password
|
||||||
|
v-model="formDate.password"
|
||||||
|
:placeholder="$t('add.user.info.password.placeholder')"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '密码不能为空',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="phone" :label="$t('add.user.info.phone')">
|
||||||
|
<a-input
|
||||||
|
v-model="formDate.phone"
|
||||||
|
:placeholder="$t('add.user.info.phone.placeholder')"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '手机号码不能为空',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="email" :label="$t('add.user.info.email')">
|
||||||
|
<a-input
|
||||||
|
v-model="formDate.email"
|
||||||
|
:placeholder="$t('add.user.info.email.placeholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="nickName" :label="$t('add.user.info.nickName')">
|
||||||
|
<a-input
|
||||||
|
v-model="formDate.nickName"
|
||||||
|
:placeholder="$t('add.user.info.nickName.placeholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="address" :label="$t('add.user.info.address')">
|
||||||
|
<a-input
|
||||||
|
v-model="formDate.address"
|
||||||
|
:placeholder="$t('add.user.info.address.placeholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="dept" :label="$t('add.user.info.dept')">
|
||||||
|
<a-select
|
||||||
|
v-model="formDate.dept"
|
||||||
|
:placeholder="$t('add.user.info.dept.placeholder')"
|
||||||
|
>
|
||||||
|
<a-option value="user">user</a-option>
|
||||||
|
<a-option value="auditor">auditor</a-option>
|
||||||
|
<a-option value="admin">admin</a-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed, reactive, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
|
||||||
|
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||||
|
import { useRoleStore } from '@/store';
|
||||||
|
import { ListParams } from '@/api/list';
|
||||||
|
import { Pagination } from '@/types/global';
|
||||||
|
import { ListRecord } from '@/api/role';
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
import useLoading from '@/hooks/loading';
|
||||||
|
import { status } from 'nprogress';
|
||||||
|
import { stat } from 'fs';
|
||||||
|
|
||||||
|
type SizeProps = 'mini' | 'small' | 'medium' | 'large';
|
||||||
|
type Column = TableColumnData & { checked?: true };
|
||||||
|
|
||||||
|
// 搜索的条件数据
|
||||||
|
const generateFormModel = () => {
|
||||||
|
return {
|
||||||
|
username: '',
|
||||||
|
phone: '',
|
||||||
|
email: '',
|
||||||
|
role: '',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { loading, setLoading } = useLoading();
|
||||||
|
const roleStore = useRoleStore();
|
||||||
|
const renderData = ref<ListRecord[]>([]);
|
||||||
|
const cloneColumns = ref<Column[]>([]);
|
||||||
|
const showColumns = ref<Column[]>([]);
|
||||||
|
const size = ref<SizeProps>('medium');
|
||||||
|
const seleteRowList = ref();
|
||||||
|
const visible = ref(false);
|
||||||
|
const messageType = ref();
|
||||||
|
let formDifer = {};
|
||||||
|
const dialogTitle = ref('添加用户');
|
||||||
|
const form = () => {
|
||||||
|
return {
|
||||||
|
id: '',
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
phone: '',
|
||||||
|
email: '',
|
||||||
|
nickName: '',
|
||||||
|
address: '',
|
||||||
|
dept: '',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const formDate = ref(form());
|
||||||
|
// 打开弹窗
|
||||||
|
const handleClick = (record: any, type: string) => {
|
||||||
|
if (type === 'modify') {
|
||||||
|
messageType.value = 'modify';
|
||||||
|
formDifer = record;
|
||||||
|
formDate.value = { ...record };
|
||||||
|
dialogTitle.value = '修改用户信息';
|
||||||
|
}
|
||||||
|
visible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 做出只修改的部分
|
||||||
|
const diffDataForm = (newData: any, oldData: any) => {
|
||||||
|
const result = {}; // 报错修改的字段内容
|
||||||
|
Object.keys(oldData).forEach((key) => {
|
||||||
|
if (oldData[key] !== newData[key] || key === 'id') {
|
||||||
|
result[key] = newData[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
const handleBeforeOk = async (done: any) => {
|
||||||
|
try {
|
||||||
|
formDifer = diffDataForm(formDate.value, formDifer);
|
||||||
|
|
||||||
|
if (dialogTitle.value === '修改用户信息') {
|
||||||
|
const res = await roleStore.updateUser(formDifer);
|
||||||
|
if (res.status === 200) {
|
||||||
|
Message.success({
|
||||||
|
content: t('add.user.info.sucess'),
|
||||||
|
duration: 3 * 1000,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Message.error({
|
||||||
|
content: t('add.user.info.fail'),
|
||||||
|
duration: 3 * 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const res = await roleStore.addUser(formDate.value);
|
||||||
|
if (res.status === 200) {
|
||||||
|
Message.success({
|
||||||
|
content: t('modify.user.info.sucess'),
|
||||||
|
duration: 3 * 1000,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Message.error({
|
||||||
|
content: t('modify.user.info.fail'),
|
||||||
|
duration: 3 * 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// you can report use errorHandler or other
|
||||||
|
} finally {
|
||||||
|
formDate.value = form();
|
||||||
|
search();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 是否启用
|
||||||
|
const enabledStatus = async (record: string) => {
|
||||||
|
const res = await roleStore.enabledStatus(record.id);
|
||||||
|
search();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择
|
||||||
|
const selectRow = (rowKeys: string[]) => {
|
||||||
|
seleteRowList.value = rowKeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
const handleDelete = async () => {
|
||||||
|
const res = await roleStore.deleteUser(seleteRowList.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const handleCancel = () => {
|
||||||
|
formDate.value = form();
|
||||||
|
visible.value = false;
|
||||||
|
dialogTitle.value = '添加用户';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 映射到formModel
|
||||||
|
const formModel = ref(generateFormModel());
|
||||||
|
|
||||||
|
// 基础分页查询的信息
|
||||||
|
const basePagination: Pagination = {
|
||||||
|
page: 1,
|
||||||
|
size: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
const pagination = reactive({
|
||||||
|
...basePagination,
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
const onPageChange = (current: number) => {
|
||||||
|
const page = current;
|
||||||
|
fetchData({ ...basePagination, page });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 调用接口请求数据
|
||||||
|
const fetchData = async (params: { page: 1; size: 10 }) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const { data } = await roleStore.getUserInfo(params);
|
||||||
|
renderData.value = data.list;
|
||||||
|
pagination.page = params.page;
|
||||||
|
pagination.total = data.total;
|
||||||
|
} catch (err) {
|
||||||
|
// you can report use errorHandler or other
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
const search = () => {
|
||||||
|
fetchData({
|
||||||
|
...basePagination,
|
||||||
|
...formModel.value,
|
||||||
|
} as unknown as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
search();
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
const reset = () => {
|
||||||
|
formModel.value = generateFormModel();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格
|
||||||
|
const columns = computed<TableColumnData[]>(() => [
|
||||||
|
{
|
||||||
|
title: t('searchTable.columns.index'),
|
||||||
|
dataIndex: 'index',
|
||||||
|
slotName: 'index',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('searchTable.columns.username'),
|
||||||
|
dataIndex: 'username',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('searchTable.columns.phone'),
|
||||||
|
dataIndex: 'phone',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('searchTable.columns.email'),
|
||||||
|
dataIndex: 'email',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('searchTable.columns.nickName'),
|
||||||
|
dataIndex: 'nickName',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('searchTable.columns.address'),
|
||||||
|
dataIndex: 'address',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('searchTable.columns.enabled'),
|
||||||
|
dataIndex: 'enabled',
|
||||||
|
slotName: 'enabled',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('searchTable.columns.operations'),
|
||||||
|
dataIndex: 'operations',
|
||||||
|
slotName: 'operations',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 将表格数据可视化
|
||||||
|
watch(
|
||||||
|
() => columns.value,
|
||||||
|
(val) => {
|
||||||
|
cloneColumns.value = val;
|
||||||
|
cloneColumns.value.forEach((item, index) => {
|
||||||
|
item.checked = true;
|
||||||
|
});
|
||||||
|
showColumns.value = cloneColumns.value;
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
|
// 用户身份
|
||||||
|
const roleOptions = computed<SelectOptionData[]>(() => [
|
||||||
|
{
|
||||||
|
label: t('searchTable.form.role.user'),
|
||||||
|
vlaue: 'user',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('searchTable.form.role.auditor'),
|
||||||
|
vlaue: 'auditor',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'Manage',
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.container {
|
||||||
|
padding: 0 20px 20px 20px;
|
||||||
|
}
|
||||||
|
</style>
|
45
src/views/character/manage/locale/en-US.ts
Normal file
45
src/views/character/manage/locale/en-US.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
export default {
|
||||||
|
'menu.list.searchTable': 'Search Table',
|
||||||
|
'menu.role.manage': 'Role Manage',
|
||||||
|
'searchTable.form.number': 'Set Number',
|
||||||
|
'searchTable.form.number.placeholder': 'Please enter Set Number',
|
||||||
|
'searchTable.form.name': 'Set Name',
|
||||||
|
'searchTable.form.name.placeholder': 'Please enter Set Name',
|
||||||
|
'searchTable.form.contentType': 'Content Type',
|
||||||
|
'searchTable.form.contentType.img': 'image-text',
|
||||||
|
'searchTable.form.contentType.horizontalVideo': 'Horizontal short video',
|
||||||
|
'searchTable.form.contentType.verticalVideo': 'Vertical short video',
|
||||||
|
'searchTable.form.filterType': 'Filter Type',
|
||||||
|
'searchTable.form.filterType.artificial': 'artificial',
|
||||||
|
'searchTable.form.filterType.rules': 'Rules',
|
||||||
|
'searchTable.form.createdTime': 'Create Date',
|
||||||
|
'searchTable.form.status': 'Status',
|
||||||
|
'searchTable.form.status.online': 'Online',
|
||||||
|
'searchTable.form.status.offline': 'Offline',
|
||||||
|
'searchTable.form.search': 'Search',
|
||||||
|
'searchTable.form.reset': 'Reset',
|
||||||
|
'searchTable.form.selectDefault': 'All',
|
||||||
|
'searchTable.operation.create': 'Create',
|
||||||
|
'searchTable.operation.import': 'Import',
|
||||||
|
'searchTable.operation.download': 'Download',
|
||||||
|
// columns
|
||||||
|
'searchTable.columns.index': '#',
|
||||||
|
'searchTable.columns.number': 'Set Number',
|
||||||
|
'searchTable.columns.name': 'Set Name',
|
||||||
|
'searchTable.columns.contentType': 'Content Type',
|
||||||
|
'searchTable.columns.filterType': 'Filter Type',
|
||||||
|
'searchTable.columns.count': 'Count',
|
||||||
|
'searchTable.columns.createdTime': 'CreatedTime',
|
||||||
|
'searchTable.columns.status': 'Status',
|
||||||
|
'searchTable.columns.operations': 'Operations',
|
||||||
|
'searchTable.columns.operations.view': 'View',
|
||||||
|
// size
|
||||||
|
'searchTable.size.mini': 'mini',
|
||||||
|
'searchTable.size.small': 'small',
|
||||||
|
'searchTable.size.medium': 'middle',
|
||||||
|
'searchTable.size.large': 'large',
|
||||||
|
// actions
|
||||||
|
'searchTable.actions.refresh': 'refresh',
|
||||||
|
'searchTable.actions.density': 'density',
|
||||||
|
'searchTable.actions.columnSetting': 'columnSetting',
|
||||||
|
};
|
46
src/views/character/manage/locale/zh-CN.ts
Normal file
46
src/views/character/manage/locale/zh-CN.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
export default {
|
||||||
|
'menu.list.searchTable': '查询表格',
|
||||||
|
'menu.role.manage': '角色管理',
|
||||||
|
'roleManage.username': '用户名',
|
||||||
|
'searchTable.form.username': '用户名',
|
||||||
|
'searchTable.form.username.placeholder': '请输入用户名',
|
||||||
|
'searchTable.form.phone': '电话号码',
|
||||||
|
'searchTable.form.phone.placeholder': '请输入电话号码',
|
||||||
|
'searchTable.form.role': '角色',
|
||||||
|
'searchTable.form.role.placeholder': '请选择角色',
|
||||||
|
'searchTable.form.role.user': '普通用户',
|
||||||
|
'searchTable.form.email': 'Email',
|
||||||
|
'searchTable.form.email.placeholder': '请输入Email',
|
||||||
|
'searchTable.form.role.auditor': '审核员',
|
||||||
|
'searchTable.form.search': '查询',
|
||||||
|
'searchTable.form.reset': '重置',
|
||||||
|
'searchTable.columns.nickName': '昵称',
|
||||||
|
'searchTable.columns.username': '用户名',
|
||||||
|
'searchTable.columns.phone': '电话',
|
||||||
|
'searchTable.columns.email': 'Email',
|
||||||
|
'searchTable.columns.enabled': '是否启用',
|
||||||
|
'searchTable.columns.avater': '头像',
|
||||||
|
'searchTable.columns.address': '地址',
|
||||||
|
'searchTable.columns.operations.detail': '详细',
|
||||||
|
'searchTable.operation.create': '添加',
|
||||||
|
'searchTable.operation.delete': '删除',
|
||||||
|
'add.user.info': '添加用户',
|
||||||
|
'add.user.info.username': '用户名',
|
||||||
|
'add.user.info.username.placeholder': '请输入用户名',
|
||||||
|
'add.user.info.password': '密码',
|
||||||
|
'add.user.info.password.placeholder': '请输入密码',
|
||||||
|
'add.user.info.phone': '电话号码',
|
||||||
|
'add.user.info.phone.placeholder': '请输入电话号码',
|
||||||
|
'add.user.info.email': 'Email',
|
||||||
|
'add.user.info.email.placeholder': '请输入Email',
|
||||||
|
'add.user.info.nickName': '昵称',
|
||||||
|
'add.user.info.nickName.placeholder': '请输入昵称',
|
||||||
|
'add.user.info.address': '地址',
|
||||||
|
'add.user.info.address.placeholder': '请输入地址',
|
||||||
|
'add.user.info.dept': '角色',
|
||||||
|
'add.user.info.dept.placeholder': '请选择角色',
|
||||||
|
'add.user.info.sucess': '添加成功',
|
||||||
|
'add.user.info.fail': '添加失败',
|
||||||
|
'modify.user.info.sucess': '修改成功',
|
||||||
|
'modify.user.info.fail': '修改失败',
|
||||||
|
};
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-form-wrapper">
|
<div class="login-form-wrapper">
|
||||||
<div class="login-form-title">{{ $t('login.form.title') }}</div>
|
<div class="login-form-title">{{ $t('login.form.title') }}</div>
|
||||||
<!-- <div class="login-form-sub-title">{{ $t('login.form.title') }}</div>-->
|
<!-- <div class="login-form-sub-title">{{ $t('login.form.title') }}</div>-->
|
||||||
<!-- <div class="login-form-sub-title">请先登录</div>-->
|
<!-- <div class="login-form-sub-title">请先登录</div>-->
|
||||||
<div class="login-form-error-msg">{{ errorMessage }}</div>
|
<div class="login-form-error-msg">{{ errorMessage }}</div>
|
||||||
<a-form
|
<a-form
|
||||||
ref="loginForm"
|
ref="loginForm"
|
||||||
@ -56,6 +56,7 @@
|
|||||||
<a-button type="primary" html-type="submit" long :loading="loading">
|
<a-button type="primary" html-type="submit" long :loading="loading">
|
||||||
{{ $t('login.form.login') }}
|
{{ $t('login.form.login') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
|
|
||||||
<a-button type="text" long class="login-form-register-btn">
|
<a-button type="text" long class="login-form-register-btn">
|
||||||
{{ $t('login.form.register') }}
|
{{ $t('login.form.register') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
@ -65,103 +66,134 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { ValidatedError } from '@arco-design/web-vue/es/form/interface';
|
import { ValidatedError } from '@arco-design/web-vue/es/form/interface';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import { useUserStore } from '@/store';
|
import { useUserStore } from '@/store';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import type { LoginData } from '@/api/user';
|
import { LoginData } from '@/api/user';
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const { t } = useI18n();
|
|
||||||
const errorMessage = ref('');
|
|
||||||
const { loading, setLoading } = useLoading();
|
|
||||||
const userStore = useUserStore();
|
|
||||||
|
|
||||||
const loginConfig = useStorage('login-config', {
|
|
||||||
rememberPassword: true,
|
|
||||||
username: '', // 演示默认值
|
|
||||||
password: '', // demo default value
|
|
||||||
});
|
|
||||||
const userInfo = reactive({
|
|
||||||
username: loginConfig.value.username,
|
|
||||||
password: loginConfig.value.password,
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleSubmit = async ({
|
const router = useRouter();
|
||||||
errors,
|
const { t } = useI18n();
|
||||||
values,
|
const errorMessage = ref('');
|
||||||
}: {
|
const { loading, setLoading } = useLoading();
|
||||||
errors: Record<string, ValidatedError> | undefined;
|
const userStore = useUserStore();
|
||||||
values: Record<string, any>;
|
|
||||||
}) => {
|
const loginConfig = useStorage('login-config', {
|
||||||
if (loading.value) return;
|
// 使用 useStorage 创建一个响应式变量,存储登录相关配置
|
||||||
if (!errors) {
|
rememberPassword: true,
|
||||||
setLoading(true);
|
username: '', // 演示默认值
|
||||||
try {
|
password: '', // demo default value
|
||||||
await userStore.login(values as LoginData);
|
});
|
||||||
const { redirect, ...othersQuery } = router.currentRoute.value.query;
|
|
||||||
router.push({
|
const userInfo = reactive({
|
||||||
name: (redirect as string) || 'Workplace',
|
// 创建一个响应式对象,反映 loginConfig 中的 username 和 password
|
||||||
query: {
|
username: loginConfig.value.username,
|
||||||
...othersQuery,
|
password: loginConfig.value.password,
|
||||||
},
|
});
|
||||||
});
|
|
||||||
Message.success(t('login.form.login.success'));
|
const handleSubmit = async ({
|
||||||
const { rememberPassword } = loginConfig.value;
|
// 处理表单提交的异步函数
|
||||||
const { username, password } = values;
|
errors,
|
||||||
// 实际生产环境需要进行加密存储。
|
values,
|
||||||
// The actual production environment requires encrypted storage.
|
}: {
|
||||||
loginConfig.value.username = rememberPassword ? username : '';
|
errors: Record<string, ValidatedError> | undefined;
|
||||||
loginConfig.value.password = rememberPassword ? password : '';
|
values: Record<string, any>;
|
||||||
} catch (err) {
|
}) => {
|
||||||
// errorMessage.value = (err as Error).message;
|
// 如果正在加载中,提前返回
|
||||||
errorMessage.value = '登录失败';
|
if (loading.value) return;
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
// 如果没有表单验证错误
|
||||||
}
|
if (!errors) {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await userStore.me();
|
||||||
|
|
||||||
|
// console.log('e', res.data.csrf);
|
||||||
|
// await userCsrf.update(res)
|
||||||
|
// userCsrf.content = res.data.csrf;
|
||||||
|
// 尝试使用 userStore.login 方法进行登录
|
||||||
|
await userStore.login(
|
||||||
|
values as LoginData,
|
||||||
|
res.data.csrf.headerName,
|
||||||
|
res.data.csrf.token
|
||||||
|
);
|
||||||
|
|
||||||
|
const csrf = await userStore.me();
|
||||||
|
// console.log('vue', csrf.data.csrf);
|
||||||
|
// userCsrf.content = csrf.data.csrf;
|
||||||
|
// let {crsf} = storeToRefs(userStore)
|
||||||
|
// useUserStore.user.csrf = csrf.data.csrf;
|
||||||
|
|
||||||
|
// 获取路由信息,处理重定向
|
||||||
|
const { redirect, ...othersQuery } = router.currentRoute.value.query;
|
||||||
|
router.push({
|
||||||
|
name: 'Workplace',
|
||||||
|
query: {
|
||||||
|
...othersQuery,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示登录成功的消息
|
||||||
|
Message.success(t('login.form.login.success'));
|
||||||
|
const { rememberPassword } = loginConfig.value;
|
||||||
|
const { username, password } = values;
|
||||||
|
|
||||||
|
// 实际生产环境需要进行加密存储。
|
||||||
|
// The actual production environment requires encrypted storage.
|
||||||
|
loginConfig.value.username = rememberPassword ? username : '';
|
||||||
|
loginConfig.value.password = rememberPassword ? password : '';
|
||||||
|
} catch (err) {
|
||||||
|
// errorMessage.value = (err as Error).message;
|
||||||
|
errorMessage.value = '登录失败';
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
const setRememberPassword = (value: boolean) => {
|
};
|
||||||
loginConfig.value.rememberPassword = value;
|
const setRememberPassword = (value: boolean) => {
|
||||||
};
|
loginConfig.value.rememberPassword = value;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.login-form {
|
.login-form {
|
||||||
&-wrapper {
|
&-wrapper {
|
||||||
width: 320px;
|
width: 320px;
|
||||||
}
|
|
||||||
|
|
||||||
&-title {
|
|
||||||
color: var(--color-text-1);
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-sub-title {
|
|
||||||
color: var(--color-text-3);
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-error-msg {
|
|
||||||
height: 32px;
|
|
||||||
color: rgb(var(--red-6));
|
|
||||||
line-height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-password-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-register-btn {
|
|
||||||
color: var(--color-text-3) !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
color: var(--color-text-1);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-sub-title {
|
||||||
|
color: var(--color-text-3);
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-error-msg {
|
||||||
|
height: 32px;
|
||||||
|
color: rgb(var(--red-6));
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-password-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-register-btn {
|
||||||
|
color: var(--color-text-3) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
'login.form.title': '中山学院学习平台',
|
'login.form.title': '学院学习平台',
|
||||||
'login.form.userName.errMsg': '用户名不能为空',
|
'login.form.userName.errMsg': '用户名不能为空',
|
||||||
'login.form.password.errMsg': '密码不能为空',
|
'login.form.password.errMsg': '密码不能为空',
|
||||||
'login.form.login.errMsg': '登录出错,请刷新重试',
|
'login.form.login.errMsg': '登录出错,请刷新重试',
|
||||||
|
@ -8,24 +8,26 @@
|
|||||||
<img :src="userInfo.avatar" />
|
<img :src="userInfo.avatar" />
|
||||||
</a-avatar>
|
</a-avatar>
|
||||||
<a-typography-title :heading="6" style="margin: 0">
|
<a-typography-title :heading="6" style="margin: 0">
|
||||||
{{ userInfo.username }}
|
{{ userInfo.nickName }}
|
||||||
</a-typography-title>
|
</a-typography-title>
|
||||||
<div class="user-msg">
|
<div class="user-msg">
|
||||||
<a-space :size="18">
|
<a-space :size="18">
|
||||||
<div>
|
<div>
|
||||||
<icon-user />
|
<icon-phone />
|
||||||
<a-typography-text>{{ userInfo.username }}</a-typography-text>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<icon-home />
|
|
||||||
<a-typography-text>
|
<a-typography-text>
|
||||||
{{ userInfo.phone }}
|
{{ userInfo.phone }}
|
||||||
</a-typography-text>
|
</a-typography-text>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div>-->
|
<div>
|
||||||
<!-- <icon-location />-->
|
<icon-email />
|
||||||
<!-- <a-typography-text>{{ userInfo.locationName }}</a-typography-text>-->
|
<a-typography-text>
|
||||||
<!-- </div>-->
|
{{ userInfo.email }}
|
||||||
|
</a-typography-text>
|
||||||
|
</div>
|
||||||
|
<!-- <div>-->
|
||||||
|
<!-- <icon-location />-->
|
||||||
|
<!-- <a-typography-text>{{ userInfo.locationName }}</a-typography-text>-->
|
||||||
|
<!-- </div>-->
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
</a-space>
|
</a-space>
|
||||||
@ -33,37 +35,37 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useUserStore } from '@/store';
|
import { useUserStore } from '@/store';
|
||||||
|
|
||||||
const userInfo = useUserStore();
|
const userInfo = useUserStore();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 204px;
|
height: 204px;
|
||||||
color: var(--gray-10);
|
color: var(--gray-10);
|
||||||
background: url(//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/41c6b125cc2e27021bf7fcc9a9b1897c.svg~tplv-49unhts6dw-image.image)
|
background: url(//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/41c6b125cc2e27021bf7fcc9a9b1897c.svg~tplv-49unhts6dw-image.image)
|
||||||
no-repeat;
|
no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
:deep(.arco-avatar-trigger-icon-button) {
|
:deep(.arco-avatar-trigger-icon-button) {
|
||||||
color: rgb(var(--arcoblue-6));
|
color: rgb(var(--arcoblue-6));
|
||||||
|
|
||||||
:deep(.arco-icon) {
|
:deep(.arco-icon) {
|
||||||
vertical-align: -1px;
|
vertical-align: -1px;
|
||||||
}
|
|
||||||
}
|
|
||||||
.user-msg {
|
|
||||||
.arco-icon {
|
|
||||||
color: rgb(var(--gray-10));
|
|
||||||
}
|
|
||||||
.arco-typography {
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.user-msg {
|
||||||
|
.arco-icon {
|
||||||
|
color: rgb(var(--gray-10));
|
||||||
|
}
|
||||||
|
.arco-typography {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
field="name"
|
field="nickName"
|
||||||
label="昵称"
|
label="昵称"
|
||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
@ -48,13 +48,13 @@
|
|||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
v-model="formData.name"
|
v-model="formData.nickName"
|
||||||
:placeholder="$t('userSetting.basicInfo.placeholder.nickname')"
|
:placeholder="$t('userSetting.basicInfo.placeholder.nickname')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
field="profile"
|
field="address"
|
||||||
label="备注"
|
label="地址"
|
||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
maxLength: 200,
|
maxLength: 200,
|
||||||
@ -63,7 +63,7 @@
|
|||||||
]"
|
]"
|
||||||
row-class="keep-margin"
|
row-class="keep-margin"
|
||||||
>
|
>
|
||||||
<a-textarea v-model="formData.remark" />
|
<a-textarea v-model="formData.address" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-space>
|
<a-space>
|
||||||
@ -79,41 +79,41 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useUserStore } from '@/store';
|
import { useUserStore } from '@/store';
|
||||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||||
import { UserState } from '@/store/modules/user/types';
|
import { UserState } from '@/store/modules/user/types';
|
||||||
import { selfUpdate } from '@/api/user';
|
import { selfUpdate } from '@/api/user';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const formData = ref<UserState>({
|
const formData = ref<UserState>({
|
||||||
...userStore.userInfo,
|
...userStore.userInfo,
|
||||||
});
|
});
|
||||||
const validate = async () => {
|
const validate = async () => {
|
||||||
const valid = await formRef.value?.validate();
|
const valid = await formRef.value?.validate();
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
// do some thing
|
// do some thing
|
||||||
// you also can use html-type to submit
|
// you also can use html-type to submit
|
||||||
const res = await selfUpdate(formData.value);
|
const res = await selfUpdate(formData.value);
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
Message.success({
|
Message.success({
|
||||||
content: '编辑成功',
|
content: '编辑成功',
|
||||||
duration: 5 * 1000,
|
duration: 5 * 1000,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
const reset = async () => {
|
};
|
||||||
await formRef.value?.resetFields();
|
const reset = async () => {
|
||||||
};
|
await formRef.value?.resetFields();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.form {
|
.form {
|
||||||
width: 540px;
|
width: 540px;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -7,13 +7,26 @@
|
|||||||
:wrapper-col-props="{ span: 16 }"
|
:wrapper-col-props="{ span: 16 }"
|
||||||
>
|
>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
field="newPassword"
|
field="oldPassword"
|
||||||
|
:label="$t('userSetting.passwordReset.form.label.oldPassword')"
|
||||||
|
:rules="[{ required: true, message: $t('login.form.password.errMsg') }]"
|
||||||
|
>
|
||||||
|
<a-input-password
|
||||||
|
v-model="formData.oldPassword"
|
||||||
|
placeholder="请输入原密码"
|
||||||
|
allow-clear
|
||||||
|
>
|
||||||
|
</a-input-password>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
field="password"
|
||||||
:label="$t('userSetting.passwordReset.form.label.newPassword')"
|
:label="$t('userSetting.passwordReset.form.label.newPassword')"
|
||||||
:rules="[{ required: true, message: $t('login.form.password.errMsg') }]"
|
:rules="[{ required: true, message: $t('login.form.password.errMsg') }]"
|
||||||
:validate-trigger="['change', 'blur']"
|
:validate-trigger="['change', 'blur']"
|
||||||
>
|
>
|
||||||
<a-input-password
|
<a-input-password
|
||||||
v-model="formData.newPassword"
|
v-model="formData.password"
|
||||||
placeholder="请输入新密码"
|
placeholder="请输入新密码"
|
||||||
allow-clear
|
allow-clear
|
||||||
>
|
>
|
||||||
@ -46,55 +59,58 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||||
import { PasswordReSetModel, resetPassword } from '@/api/user';
|
import { PasswordReSetModel, resetPassword } from '@/api/user';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import useUser from "@/hooks/user";
|
import useUser from '@/hooks/user';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const formData = ref<PasswordReSetModel>({
|
const formData = ref<PasswordReSetModel>({
|
||||||
newPassword: '',
|
oldPassword: '',
|
||||||
confirmPassword: '',
|
password: '',
|
||||||
});
|
confirmPassword: '',
|
||||||
const checkEquals = (
|
});
|
||||||
value: string | undefined,
|
const checkEquals = (
|
||||||
callback: (error?: string) => void
|
value: string | undefined,
|
||||||
) => {
|
callback: (error?: string) => void
|
||||||
if (!value) {
|
) => {
|
||||||
callback(t('userSetting.passwordReset.form.validate.blank'));
|
if (!value) {
|
||||||
} else if (formData.value.newPassword !== formData.value.confirmPassword) {
|
callback(t('userSetting.passwordReset.form.validate.blank'));
|
||||||
callback(t('userSetting.passwordReset.form.validate.noEquals'));
|
} else if (formData.value.password !== formData.value.confirmPassword) {
|
||||||
|
callback(t('userSetting.passwordReset.form.validate.noEquals'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const user = useUser();
|
||||||
|
const validate = async () => {
|
||||||
|
const vali = await formRef.value?.validate();
|
||||||
|
if (!vali) {
|
||||||
|
// do some thing
|
||||||
|
// you also can use html-type to submit
|
||||||
|
|
||||||
|
const res = await resetPassword(formData.value);
|
||||||
|
if (res.status === 200) {
|
||||||
|
Message.success({
|
||||||
|
content: res.data,
|
||||||
|
duration: 5 * 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
// await user.logout();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
const user = useUser();
|
const reset = async () => {
|
||||||
const validate = async () => {
|
await formRef.value?.resetFields();
|
||||||
const vali = await formRef.value?.validate();
|
};
|
||||||
if (!vali) {
|
|
||||||
// do some thing
|
|
||||||
// you also can use html-type to submit
|
|
||||||
const res = await resetPassword(formData.value);
|
|
||||||
if (res.status === 200) {
|
|
||||||
Message.success({
|
|
||||||
content: res.data,
|
|
||||||
duration: 5 * 1000,
|
|
||||||
});
|
|
||||||
await user.logout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const reset = async () => {
|
|
||||||
await formRef.value?.resetFields();
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.form {
|
.form {
|
||||||
width: 540px;
|
width: 540px;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -45,6 +45,7 @@ export default {
|
|||||||
'userSetting.basicInfo.placeholder.profile':
|
'userSetting.basicInfo.placeholder.profile':
|
||||||
'Please enter your profile, no more than 200 words',
|
'Please enter your profile, no more than 200 words',
|
||||||
'userSetting.form.error.profile.maxLength': 'No more than 200 words',
|
'userSetting.form.error.profile.maxLength': 'No more than 200 words',
|
||||||
|
'userSetting.passwordReset.form.label.oldPassword': 'Orinal Password',
|
||||||
'userSetting.SecuritySettings.form.label.password': 'Login Password',
|
'userSetting.SecuritySettings.form.label.password': 'Login Password',
|
||||||
'userSetting.SecuritySettings.placeholder.password':
|
'userSetting.SecuritySettings.placeholder.password':
|
||||||
'Has been set. The password must contain at least six letters, digits, and special characters except Spaces. The password must contain both uppercase and lowercase letters.',
|
'Has been set. The password must contain at least six letters, digits, and special characters except Spaces. The password must contain both uppercase and lowercase letters.',
|
||||||
|
@ -33,6 +33,7 @@ export default {
|
|||||||
'userSetting.basicInfo.placeholder.profile':
|
'userSetting.basicInfo.placeholder.profile':
|
||||||
'请输入您的个人简介,最多不超过200字。',
|
'请输入您的个人简介,最多不超过200字。',
|
||||||
'userSetting.form.error.profile.maxLength': '最多不超过200字',
|
'userSetting.form.error.profile.maxLength': '最多不超过200字',
|
||||||
|
'userSetting.passwordReset.form.label.oldPassword': '原密码',
|
||||||
'userSetting.passwordReset.form.label.newPassword': '新密码',
|
'userSetting.passwordReset.form.label.newPassword': '新密码',
|
||||||
'userSetting.passwordReset.form.label.confirmPassword': '确认新密码',
|
'userSetting.passwordReset.form.label.confirmPassword': '确认新密码',
|
||||||
'userSetting.SecuritySettings.form.label.password': '登录密码',
|
'userSetting.SecuritySettings.form.label.password': '登录密码',
|
||||||
|
Loading…
Reference in New Issue
Block a user