From 4b56e055369319da8b88f35b414b5902238d17b2 Mon Sep 17 00:00:00 2001 From: soul2 Date: Mon, 12 Oct 2026 14:31:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(demo):=20=E6=81=A2=E5=A4=8D=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E7=99=BB=E5=BD=95=E9=89=B4=E6=9D=83=E5=B9=B6=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=A8=A1=E6=9D=BF=E9=85=8D=E7=BD=AE=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 恢复 permission.js 路由守卫,未登录访问自动跳转登录页 - 登录、用户信息、注销接口由 mock 路径改为后端 /auth 接口 - 请求拦截器恢复 X-Token 请求头注入,并增加 40101 登录失效处理 - 登录页移除模板自带的演示账号提示与默认填充值,标题改为千帆公众号管理后台 - 用户名校验由白名单 admin/editor 改为非空校验 - 移除生产环境构建时挂载的 mockXHR,避免劫持真实请求 - 新增 api/template.js 封装模板配置的查询、保存、删除、刷新缓存与微信模板拉取接口 - 新增模板管理页面,支持关键字筛选、新增编辑、删除、刷新缓存及从微信拉取模板自动解析关键字 - 路由新增模板管理菜单项 --- .env.development | 4 +- src/api/template.js | 62 +++++++++ src/api/user.js | 11 +- src/main.js | 13 -- src/permission.js | 128 +++++++++--------- src/router/index.js | 11 ++ src/utils/request.js | 19 ++- src/utils/validate.js | 3 +- src/views/login/index.vue | 15 +- src/views/template/index.vue | 256 +++++++++++++++++++++++++++++++++++ 10 files changed, 415 insertions(+), 107 deletions(-) create mode 100644 src/api/template.js create mode 100644 src/views/template/index.vue diff --git a/.env.development b/.env.development index bba8782..22e103f 100644 --- a/.env.development +++ b/.env.development @@ -2,5 +2,5 @@ ENV = 'development' # base api -#VUE_APP_BASE_API = 'http://localhost:7710/wxmessage' -VUE_APP_BASE_API = 'https://alumni.zdxh.cn/kj/wxmessage' +VUE_APP_BASE_API = 'http://localhost:7710/wxmessage' +#VUE_APP_BASE_API = 'https://alumni.zdxh.cn/kj/wxmessage' diff --git a/src/api/template.js b/src/api/template.js new file mode 100644 index 0000000..758f6fb --- /dev/null +++ b/src/api/template.js @@ -0,0 +1,62 @@ +import request from '@/utils/request' + +/** + * 模板列表 + * @param data { onlyEnabled, keyword } + */ +export function page(data) { + return request({ + url: '/template/list', + data + }) +} + +/** + * 模板详情 + */ +export function detail(id) { + return request({ + url: `/template/detail/${id}`, + method: 'get' + }) +} + +/** + * 新增或更新模板 + */ +export function save(data) { + return request({ + url: '/template/save', + data + }) +} + +/** + * 删除模板 + */ +export function remove(id) { + return request({ + url: `/template/delete/${id}`, + data: {} + }) +} + +/** + * 刷新发送缓存 + */ +export function refresh() { + return request({ + url: '/template/refresh', + data: {} + }) +} + +/** + * 从微信拉取当前公众号的模板列表 + */ +export function wechatList() { + return request({ + url: '/template/wechat/list', + data: {} + }) +} diff --git a/src/api/user.js b/src/api/user.js index 8ff4389..fe6e55c 100644 --- a/src/api/user.js +++ b/src/api/user.js @@ -2,23 +2,22 @@ import request from '@/utils/request' export function login(data) { return request({ - url: '/vue-admin-template/user/login', + url: '/auth/login', method: 'post', data }) } -export function getInfo(token) { +export function getInfo() { return request({ - url: '/vue-admin-template/user/info', - method: 'get', - params: { token } + url: '/auth/info', + method: 'get' }) } export function logout() { return request({ - url: '/vue-admin-template/user/logout', + url: '/auth/logout', method: 'post' }) } diff --git a/src/main.js b/src/main.js index 9814e0a..60a4bbc 100644 --- a/src/main.js +++ b/src/main.js @@ -12,19 +12,6 @@ import '@/icons' // icon import '@/permission' // permission control import elementGlobal from './element-ui-global' -/** - * If you don't want to use mock-server - * you want to use MockJs for mock api - * you can execute: mockXHR() - * - * Currently MockJs will be used in the production environment, - * please remove it before going online ! ! ! - */ -if (process.env.NODE_ENV === 'production') { - const { mockXHR } = require('../mock') - mockXHR() -} - // set ElementUI lang to EN // Vue.use(ElementUI, { locale }) // 如果想要中文版 element-ui,按如下方式声明 diff --git a/src/permission.js b/src/permission.js index 963621f..fa1ea19 100644 --- a/src/permission.js +++ b/src/permission.js @@ -1,64 +1,64 @@ -// import router from './router' -// import store from './store' -// import { Message } from 'element-ui' -// import NProgress from 'nprogress' // progress bar -// import 'nprogress/nprogress.css' // progress bar style -// import { getToken } from '@/utils/auth' // get token from cookie -// import getPageTitle from '@/utils/get-page-title' -// -// NProgress.configure({ showSpinner: false }) // NProgress Configuration -// -// const whiteList = ['/login'] // no redirect whitelist -// -// router.beforeEach(async(to, from, next) => { -// // start progress bar -// NProgress.start() -// -// // set page title -// document.title = getPageTitle(to.meta.title) -// -// // determine whether the user has logged in -// const hasToken = getToken() -// -// if (hasToken) { -// if (to.path === '/login') { -// // if is logged in, redirect to the home page -// next({ path: '/' }) -// NProgress.done() -// } else { -// const hasGetUserInfo = store.getters.name -// if (hasGetUserInfo) { -// next() -// } else { -// try { -// // get user info -// await store.dispatch('user/getInfo') -// -// next() -// } catch (error) { -// // remove token and go to login page to re-login -// await store.dispatch('user/resetToken') -// Message.error(error || 'Has Error') -// next(`/login?redirect=${to.path}`) -// NProgress.done() -// } -// } -// } -// } else { -// /* has no token*/ -// -// if (whiteList.indexOf(to.path) !== -1) { -// // in the free login whitelist, go directly -// next() -// } else { -// // other pages that do not have permission to access are redirected to the login page. -// next(`/login?redirect=${to.path}`) -// NProgress.done() -// } -// } -// }) -// -// router.afterEach(() => { -// // finish progress bar -// NProgress.done() -// }) +import router from './router' +import store from './store' +import { Message } from 'element-ui' +import NProgress from 'nprogress' // progress bar +import 'nprogress/nprogress.css' // progress bar style +import { getToken } from '@/utils/auth' // get token from cookie +import getPageTitle from '@/utils/get-page-title' + +NProgress.configure({ showSpinner: false }) // NProgress Configuration + +const whiteList = ['/login'] // no redirect whitelist + +router.beforeEach(async(to, from, next) => { + // start progress bar + NProgress.start() + + // set page title + document.title = getPageTitle(to.meta.title) + + // determine whether the user has logged in + const hasToken = getToken() + + if (hasToken) { + if (to.path === '/login') { + // if is logged in, redirect to the home page + next({ path: '/' }) + NProgress.done() + } else { + const hasGetUserInfo = store.getters.name + if (hasGetUserInfo) { + next() + } else { + try { + // get user info + await store.dispatch('user/getInfo') + + next() + } catch (error) { + // remove token and go to login page to re-login + await store.dispatch('user/resetToken') + Message.error(error || 'Has Error') + next(`/login?redirect=${to.path}`) + NProgress.done() + } + } + } + } else { + /* has no token*/ + + if (whiteList.indexOf(to.path) !== -1) { + // in the free login whitelist, go directly + next() + } else { + // other pages that do not have permission to access are redirected to the login page. + next(`/login?redirect=${to.path}`) + NProgress.done() + } + } +}) + +router.afterEach(() => { + // finish progress bar + NProgress.done() +}) diff --git a/src/router/index.js b/src/router/index.js index 6c55faa..f14ad61 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -54,6 +54,17 @@ export const constantRoutes = [ }] }, + { + path: '/template', + component: Layout, + children: [{ + path: 'index', + name: 'Template', + component: () => import('@/views/template/index'), + meta: { title: '模板管理', icon: 'form' } + }] + }, + // { // path: '/dfadfa', // component: Layout, diff --git a/src/utils/request.js b/src/utils/request.js index 9161eb1..853ca72 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -1,6 +1,7 @@ import axios from 'axios' import { Message, MessageBox } from 'element-ui' import store from '@/store' +import { getToken } from '@/utils/auth' // create an axios instance const service = axios.create({ @@ -16,14 +17,11 @@ const service = axios.create({ // request interceptor service.interceptors.request.use( config => { - // do something before request is sent - - // if (store.getters.token) { - // // let each request carry token - // // ['X-Token'] is a custom headers key - // // please modify it according to the actual situation - // config.headers['X-Token'] = getToken() - // } + // 每个请求携带后台登录令牌 + const token = getToken() + if (token) { + config.headers['X-Token'] = token + } return config }, error => { @@ -56,8 +54,9 @@ service.interceptors.response.use( duration: 5 * 1000 }) - // 40401:非法令牌;40402:其他客户登录;40403:令牌过期; - if (res.code === 40401 || res.code === 40402 || res.code === 40403) { + // 40101:登录信息丢失(MsgPlatform 统一鉴权返回) + // 40401:非法令牌;40402:其他客户登录;40403:令牌过期(历史遗留码,保留兼容) + if (res.code === 40101 || res.code === 40401 || res.code === 40402 || res.code === 40403) { // to re-login MessageBox.confirm('当前账户的登录信息已过期,点击“取消”按钮停留在当前页面,或重新登录', '走丢了', { confirmButtonText: '重新登录', diff --git a/src/utils/validate.js b/src/utils/validate.js index 8d962ad..bfc258e 100644 --- a/src/utils/validate.js +++ b/src/utils/validate.js @@ -15,6 +15,5 @@ export function isExternal(path) { * @returns {Boolean} */ export function validUsername(str) { - const valid_map = ['admin', 'editor'] - return valid_map.indexOf(str.trim()) >= 0 + return typeof str === 'string' && str.trim().length > 0 } diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 83b5be6..8455419 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -5,7 +5,7 @@ >
-

Login Form

+

千帆公众号管理后台

@@ -15,7 +15,7 @@ Login -
- username: admin - password: any -
- @@ -79,8 +74,8 @@ export default { } return { loginForm: { - username: 'admin', - password: '111111' + username: '', + password: '' }, loginRules: { username: [{ required: true, trigger: 'blur', validator: validateUsername }], diff --git a/src/views/template/index.vue b/src/views/template/index.vue new file mode 100644 index 0000000..a69cbd9 --- /dev/null +++ b/src/views/template/index.vue @@ -0,0 +1,256 @@ + + + + +