上传文件至「/」
This commit is contained in:
180
App.vue
Normal file
180
App.vue
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<script>
|
||||||
|
import config from '@/app.config.js';
|
||||||
|
import { version } from './package.json';
|
||||||
|
export default {
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
// 初始化菜单权限等数据
|
||||||
|
init() {
|
||||||
|
let { vk } = this;
|
||||||
|
// 如果token失效,直接跳登录页面
|
||||||
|
if (!vk.checkToken()) {
|
||||||
|
this.navigateToLogin();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this.isAllowLoginBackground()) {
|
||||||
|
vk.alert('您的账户无登陆权限', () => {
|
||||||
|
this.navigateToLogin();
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vk.userCenter.getMenu({
|
||||||
|
success: (data) => {
|
||||||
|
// 初始化菜单
|
||||||
|
let { menus = [] } = data;
|
||||||
|
// 合并去重
|
||||||
|
menus = vk.pubfn.arr_concat(menus, config.sideBar.staticMenu, 'menu_id');
|
||||||
|
// 排序
|
||||||
|
menus.sort((a, b) => {
|
||||||
|
let sortA = a.sort || 0;
|
||||||
|
let sortB = b.sort || 0;
|
||||||
|
return sortA - sortB;
|
||||||
|
});
|
||||||
|
if (JSON.stringify(menus) !== JSON.stringify(vk.getVuex('$app.navMenu'))) {
|
||||||
|
vk.setVuex('$app.navMenu', menus);
|
||||||
|
}
|
||||||
|
// 将树形结构转成数组结构
|
||||||
|
let menuList = vk.pubfn.treeToArray(menus, {
|
||||||
|
id: 'menu_id',
|
||||||
|
parent_id: 'parent_id',
|
||||||
|
children: 'children',
|
||||||
|
});
|
||||||
|
if (JSON.stringify(menuList) !== JSON.stringify(vk.getVuex('$app.menuList'))) {
|
||||||
|
vk.setVuex('$app.menuList', menuList);
|
||||||
|
}
|
||||||
|
vk.setVuex('$user.userInfo', data.userInfo);
|
||||||
|
vk.setVuex('$user.permission', data.userInfo.permission);
|
||||||
|
vk.setVuex('$app.inited', true);
|
||||||
|
this.checkCurrentAppId();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 初始化系统环境变量
|
||||||
|
initApp() {
|
||||||
|
uni.getSystemInfo().then(([err, res]) => {
|
||||||
|
let isPC = res.model && res.model != 'PC' && res.windowWidth <= 768 ? false : true;
|
||||||
|
vk.setVuex('$app.isPC', isPC);
|
||||||
|
vk.setVuex('$app.width', res.windowWidth);
|
||||||
|
vk.setVuex('$app.height', res.windowHeight);
|
||||||
|
});
|
||||||
|
uni.onWindowResize((res) => {
|
||||||
|
vk.pubfn.debounce(
|
||||||
|
() => {
|
||||||
|
vk.setVuex('$app.width', res.size.windowWidth);
|
||||||
|
vk.setVuex('$app.height', res.size.windowHeight);
|
||||||
|
let isPC = res.size.windowWidth > 768 ? true : false;
|
||||||
|
vk.setVuex('$app.isPC', isPC);
|
||||||
|
},
|
||||||
|
50,
|
||||||
|
false,
|
||||||
|
'app-onresize'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 检查是否允许登录admin后台
|
||||||
|
isAllowLoginBackground(userInfo) {
|
||||||
|
let { vk } = this;
|
||||||
|
if (!userInfo) userInfo = vk.getVuex('$user.userInfo');
|
||||||
|
let key = true;
|
||||||
|
if (vk.pubfn.isNotNull(userInfo)) {
|
||||||
|
let { role = [], allow_login_background = false } = userInfo;
|
||||||
|
if (role.indexOf('admin') == -1 && !allow_login_background) {
|
||||||
|
key = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
},
|
||||||
|
// 检测当前应用appid是否已添加到应用管理中
|
||||||
|
checkCurrentAppId() {
|
||||||
|
let { vk } = this;
|
||||||
|
let systemInfo = uni.getSystemInfoSync();
|
||||||
|
let isHome = `/${this.appOptions.path}` === config.index.url; // 是否是首页
|
||||||
|
if (systemInfo.appId && isHome && vk.checkToken() && this.$hasRole('admin')) {
|
||||||
|
vk.callFunction({
|
||||||
|
url: 'admin/system/app/sys/getInfo',
|
||||||
|
data: {
|
||||||
|
appid: systemInfo.appId,
|
||||||
|
},
|
||||||
|
success: (data) => {
|
||||||
|
if (!data.info || data.info.appid !== systemInfo.appId) {
|
||||||
|
vk.confirm(`您当前登录的应用【${systemInfo.appId}】未在已有应用列表中,是否需要去添加?`, '提示', '前往应用管理', '取消', (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
vk.navigateTo('/pages_plugs/system/app/list');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
navigateToLogin() {
|
||||||
|
// 在app.vue中必须这样获取页面地址和参数才是正确的
|
||||||
|
let { vk, appOptions = {} } = this;
|
||||||
|
let params = vk.pubfn.queryParams(appOptions.query);
|
||||||
|
let url = `/${appOptions.path}${params}`;
|
||||||
|
let uniIdRedirectUrl = encodeURIComponent(url);
|
||||||
|
vk.reLaunch(`${config.login.url}?uniIdRedirectUrl=${uniIdRedirectUrl}`);
|
||||||
|
},
|
||||||
|
// 页面跳转拦截器
|
||||||
|
pageBeforeInterceptor() {
|
||||||
|
const invoke = (args = {}) => {
|
||||||
|
if (!this.vk.checkCurrentPagePermission({ url: args.url })) {
|
||||||
|
// 跳403页面
|
||||||
|
this.vk.navigateTo403();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
uni.addInterceptor('redirectTo', { invoke });
|
||||||
|
uni.addInterceptor('navigateTo', { invoke });
|
||||||
|
uni.addInterceptor('reLaunch', { invoke });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 监听 - 页面404
|
||||||
|
onPageNotFound(e) {
|
||||||
|
uni.redirectTo({
|
||||||
|
url: config.error.url,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 监听 - 应用启动时
|
||||||
|
onLaunch: function (options) {
|
||||||
|
this.appOptions = options;
|
||||||
|
// 接收页面token参数,用于实现自动登录
|
||||||
|
this.vk.handleAutoLoginToken(options);
|
||||||
|
if (config.debug) {
|
||||||
|
console.log(
|
||||||
|
`%c vk-admin %c v${version} `,
|
||||||
|
'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
|
||||||
|
'background:#007aff ;padding: 1px; border-radius: 0 3px 3px 0; color: #fff; font-weight: bold;'
|
||||||
|
);
|
||||||
|
console.log('App Launch');
|
||||||
|
}
|
||||||
|
this.vk.pubfn.needInit({
|
||||||
|
that: this,
|
||||||
|
config,
|
||||||
|
success: () => {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.initApp();
|
||||||
|
this.pageBeforeInterceptor();
|
||||||
|
},
|
||||||
|
onShow: function () {
|
||||||
|
if (config.debug) console.log('App Show');
|
||||||
|
},
|
||||||
|
onHide: function () {
|
||||||
|
if (config.debug) console.log('App Hide');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
/**
|
||||||
|
* 每个页面公共css
|
||||||
|
* 特别注意,如果启动时报scss相关的错误,请卸载你的scss插件,重新安装
|
||||||
|
* 安装地址:https://ext.dcloud.net.cn/plugin?id=2046
|
||||||
|
*/
|
||||||
|
/* 此为uni-admin的样式,如果你不使用uni-admin的官方插件,可以不需要加载这些样式 */
|
||||||
|
@import '@/common/uni-admin/css/uni.css';
|
||||||
|
@import '@/common/uni-admin/css/uni-icons.css';
|
||||||
|
/* 此为uni-admin的样式,如果你不使用uni-admin的官方插件,可以不需要加载这些样式 */
|
||||||
|
</style>
|
||||||
205
app.config.js
Normal file
205
app.config.js
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
// 引入自定义公共函数
|
||||||
|
import myPubFunction from '@/common/function/myPubFunction.js';
|
||||||
|
// 引入静态菜单
|
||||||
|
import staticMenu from '@/app.config.menu.js';
|
||||||
|
// 引入主题配置文件
|
||||||
|
import themeConfig from '@/common/theme/index.js';
|
||||||
|
export default {
|
||||||
|
// 开发模式启用调式模式(请求时会打印日志)
|
||||||
|
debug: process.env.NODE_ENV !== 'production',
|
||||||
|
// 主云函数名称
|
||||||
|
functionName: 'router',
|
||||||
|
// 登录页面路径
|
||||||
|
login: {
|
||||||
|
url: '/pages/login/index',
|
||||||
|
// 显示在login页面的测试用户列表
|
||||||
|
testUser: {
|
||||||
|
show: false, // 是否显示
|
||||||
|
list: [
|
||||||
|
{ username: 'test11', password: '123456', nickname: '高级管理员' },
|
||||||
|
{ username: 'test12', password: '123456', nickname: '初级管理员' },
|
||||||
|
{ username: 'test13', password: '123456', nickname: '无权限用户' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 首页页面路径
|
||||||
|
index: {
|
||||||
|
url: '/pages/index/index',
|
||||||
|
},
|
||||||
|
// 404 Not Found 错误页面路径
|
||||||
|
error: {
|
||||||
|
url: '/pages_plugs/error/404',
|
||||||
|
},
|
||||||
|
// 403 无权限页面路径
|
||||||
|
noPermission: {
|
||||||
|
url: '/pages_plugs/error/403',
|
||||||
|
},
|
||||||
|
// 前端默认时区(中国为8)
|
||||||
|
targetTimezone: 8,
|
||||||
|
// 日志风格(注意:只在开发调试模式下生效,正式发布后不会打印日志)
|
||||||
|
logger: {
|
||||||
|
mode: 0, // 0 正常(默认展开) 1 简洁(默认折叠)
|
||||||
|
colorArr: ['#0095f8', '#67C23A'],
|
||||||
|
},
|
||||||
|
globalError: true, // 是否开启全局错误提示
|
||||||
|
// 需要检查是否登录的页面列表
|
||||||
|
// let { mode, list } = config.checkTokenPages
|
||||||
|
checkTokenPages: {
|
||||||
|
/**
|
||||||
|
* 如果 mode = 0 则代表自动检测
|
||||||
|
* 如果 mode = 1 则代表list内的页面需要登录,不在list内的页面不需要登录
|
||||||
|
* 如果 mode = 2 则代表list内的页面不需要登录,不在list内的页面需要登录
|
||||||
|
* 注意1: list内是通配符表达式,非正则表达式
|
||||||
|
* 在无需登录的页面上执行kh或sys函数,也会自动判断是否登录,未登录会自动跳登录页面,登录成功后会自动返回本来要跳转的页面。
|
||||||
|
*/
|
||||||
|
mode: 2,
|
||||||
|
list: ['/pages/login/*', '/pages_plugs/error/*', '/pages_template/element/*', '/pages_template/components/form/*', '/pages_template/components/icons/*'],
|
||||||
|
},
|
||||||
|
// 需要检查菜单权限的页面列表
|
||||||
|
checkPermissionPages: {
|
||||||
|
/**
|
||||||
|
* 如果 mode = 1 则代表list内的页面需要检查菜单权限,不在list内的页面不需要检查
|
||||||
|
* 如果 mode = 2 则代表list内的页面不需要检查菜单权限,不在list内的页面需要检查
|
||||||
|
* 注意: list内是通配符表达式,非正则表达式,如果一个页面不在左侧菜单中,但需要能访问,则需要在此设置
|
||||||
|
*/
|
||||||
|
mode: 2,
|
||||||
|
list: ['/pages/index/index', '/pages/login/*', '/pages_plugs/error/*'],
|
||||||
|
},
|
||||||
|
// 需要检查是否哪些请求需要加密通信
|
||||||
|
checkEncryptRequest: {
|
||||||
|
/**
|
||||||
|
* 如果 mode = 0 则不做处理
|
||||||
|
* 如果 mode = 1 则代表list内的云函数或云对象需要加密通信,不在list内的不需要加密通信
|
||||||
|
* 注意1: list内是正则表达式,非通配符表达式
|
||||||
|
* 注意2: 建议与 router/middleware/modules/encryptFilter.js 内的regExp保持一致
|
||||||
|
*/
|
||||||
|
mode: 1,
|
||||||
|
list: [
|
||||||
|
'^template/encrypt/(.*)', // 表示以 template/encrypt/ 开头的云函数或云对象需要加密通信
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// 静态文件的资源URL地址
|
||||||
|
staticUrl: {
|
||||||
|
// 顶部导航
|
||||||
|
navBar: {
|
||||||
|
// 正方形 Logo 160*160
|
||||||
|
logo: '/static/logo.png',
|
||||||
|
// 长方形 Logo 224*160
|
||||||
|
logo1: '/static/logo1.png',
|
||||||
|
// 横幅 Logo 480*100
|
||||||
|
logo2: '/static/logo2.png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 自定义公共函数,myPubFunction内的函数可通过vk.myfn.xxx() 调用
|
||||||
|
myfn: myPubFunction,
|
||||||
|
// 第三方服务配置
|
||||||
|
service: {
|
||||||
|
// 云储存相关配置
|
||||||
|
cloudStorage: {
|
||||||
|
/**
|
||||||
|
* vk.uploadFile 接口默认使用哪个存储
|
||||||
|
* unicloud 空间内置存储(默认)
|
||||||
|
* extStorage 扩展存储
|
||||||
|
* aliyun 阿里云oss
|
||||||
|
*/
|
||||||
|
defaultProvider: 'unicloud',
|
||||||
|
// 空间内置存储
|
||||||
|
unicloud: {
|
||||||
|
// 暂无配置项
|
||||||
|
},
|
||||||
|
// 扩展存储配置
|
||||||
|
extStorage: {
|
||||||
|
provider: 'qiniu', // qiniu: 扩展存储-七牛云
|
||||||
|
// 根目录名称(如果改了这里的dirname,则云函数user/pub/getUploadFileOptionsForExtStorage内判断的目录权限也要改,否则无法上传)
|
||||||
|
dirname: 'public',
|
||||||
|
// 用于鉴权的云函数地址(一般不需要改这个参数)
|
||||||
|
authAction: 'user/pub/getUploadFileOptionsForExtStorage',
|
||||||
|
// 自定义域名,如:cdn.example.com(填你在扩展存储绑定的域名,若云端已设置 uni-config-center/vk-unicloud/index.js 内的 vk.service.cloudStorage.extStorage.domain 则此处可不填)
|
||||||
|
domain: '',
|
||||||
|
// 上传时,是否按用户id进行分组储存
|
||||||
|
groupUserId: true,
|
||||||
|
},
|
||||||
|
// 阿里云oss
|
||||||
|
// 密钥和签名信息(由于签名的获取比较麻烦,建议初学者使用上传到unicloud或extStorage的方案,上传到阿里云OSS是给有特殊需求的用户使用)
|
||||||
|
// 相关文档 : https://help.aliyun.com/document_detail/31925.html?spm=a2c4g.11186623.6.1757.b7987d9czoFCVu
|
||||||
|
aliyun: {
|
||||||
|
// 密钥和签名信息
|
||||||
|
uploadData: {
|
||||||
|
OSSAccessKeyId: '',
|
||||||
|
policy: '',
|
||||||
|
signature: '',
|
||||||
|
},
|
||||||
|
// oss上传地址
|
||||||
|
action: 'https://xxx.oss-cn-hangzhou.aliyuncs.com',
|
||||||
|
// 根目录名称
|
||||||
|
dirname: 'public',
|
||||||
|
// oss外网访问地址,也可以是阿里云cdn地址
|
||||||
|
host: 'https://xxx.xxx.com',
|
||||||
|
// 上传时,是否按用户id进行分组储存
|
||||||
|
groupUserId: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 全局异常码,可以自定义提示结果
|
||||||
|
globalErrorCode: {
|
||||||
|
// 阿里云10秒非正常超时,其实请求还在执行(且一般已经成功了,但前端接受不到成功结果)
|
||||||
|
'cloudfunction-unusual-timeout': '请求超时,但请求还在执行,请重新进入页面。',
|
||||||
|
// 请求超时(真正的请求超时)
|
||||||
|
'cloudfunction-timeout': '请求超时,请重试!',
|
||||||
|
// 不在预期内的异常(如数据库异常、云函数编译异常等)
|
||||||
|
'cloudfunction-system-error': '网络开小差了!',
|
||||||
|
// 云函数达到并发限制
|
||||||
|
'cloudfunction-reaches-burst-limit': '系统繁忙,请稍后再试。',
|
||||||
|
// APP未授权网络访问时的异常提示
|
||||||
|
'cloudfunction-network-unauthorized': '需要进行网络请求许可,若您已授权,请点击确定',
|
||||||
|
},
|
||||||
|
// 页面风格
|
||||||
|
pageStyle: {
|
||||||
|
// 表单组件和表格组件的size,设为auto时,屏幕像素大于1600,则使用medium,否则使用small,且全局变量 `this.$global.size` 可获得实际生效的值
|
||||||
|
size: 'auto', // medium / small / mini / auto
|
||||||
|
},
|
||||||
|
// 左侧菜单
|
||||||
|
sideBar: {
|
||||||
|
// 配置静态菜单列表
|
||||||
|
staticMenu: staticMenu,
|
||||||
|
defaultOpeneds: ['components-admin'], // 默认展开的菜单项的 menu_id
|
||||||
|
navigateMode: 'redirectTo', // 默认 redirectTo,可选项为 navigateTo
|
||||||
|
},
|
||||||
|
// 顶部菜单
|
||||||
|
topBar: {
|
||||||
|
// 是否启用 menuTabs
|
||||||
|
showMenuTabs: true,
|
||||||
|
// logo显示模式,1 纯图片模式 2 图片+文字模式
|
||||||
|
logoMode: 1,
|
||||||
|
// logo标题
|
||||||
|
logoTitle: 'vk-admin后台管理',
|
||||||
|
},
|
||||||
|
// 主题配置
|
||||||
|
theme: {
|
||||||
|
// 当前使用哪个主题
|
||||||
|
use: 'blackWhite', // white blackWhite black custom
|
||||||
|
...themeConfig,
|
||||||
|
// 自定义主题
|
||||||
|
custom: {
|
||||||
|
// 左侧菜单样式
|
||||||
|
leftMenu: {
|
||||||
|
backgroundColor: '',
|
||||||
|
subBackgroundColor: '',
|
||||||
|
textColor: '',
|
||||||
|
activeTextColor: '',
|
||||||
|
activeBackgroundColor: '',
|
||||||
|
collapseActiveTextColor: '',
|
||||||
|
collapseActiveBackgroundColor: '',
|
||||||
|
hoverTextColor: '',
|
||||||
|
hoverBackgroundColor: '',
|
||||||
|
boxShadow: '',
|
||||||
|
borderTop: '',
|
||||||
|
},
|
||||||
|
// 顶部菜单样式
|
||||||
|
topMenu: {
|
||||||
|
backgroundColor: '',
|
||||||
|
textColor: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
13
app.config.menu.js
Normal file
13
app.config.menu.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
|
// 开发环境和正式环境中都会显示的静态菜单
|
||||||
|
import menus from './static_menu/menu.json';
|
||||||
|
// 只在开发环境中显示的静态菜单
|
||||||
|
import devMenus from './static_menu/menu-dev.json';
|
||||||
|
var menusList = [];
|
||||||
|
if (debug && devMenus) {
|
||||||
|
menusList = menus.concat(devMenus);
|
||||||
|
} else {
|
||||||
|
menusList = menus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default menusList;
|
||||||
2193
changelog.md
Normal file
2193
changelog.md
Normal file
File diff suppressed because it is too large
Load Diff
16
changelog.new.md
Normal file
16
changelog.new.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
## 1.25.0(2026-06-17)
|
||||||
|
- 【升级】`vk-unicloud-admin-ui` 的 npm 包(执行`npm i vk-unicloud-admin-ui@1.25.0 --registry https://registry.npmjs.org/`)
|
||||||
|
- 【升级】`vk依赖` [详情](https://ext.dcloud.net.cn/plugin?id=4157&update_log)
|
||||||
|
- 【重要】新增 `vk 统计` 模块,包含用户统计、支付统计、错误统计三大功能区,可通过菜单管理页「初始化vk统计」按钮一键导入菜单
|
||||||
|
- 【新增】`用户统计` 页面(概览 + 登录日志),展示新增用户趋势图、登录用户趋势图,支持按时/日/月维度切换
|
||||||
|
- 【新增】`支付统计` 页面(概览),展示收入趋势图、支付漏斗、支付方式占比饼图、按平台/订单类型收入明细表,支持日期快捷筛选和多维度筛选
|
||||||
|
- 【新增】`用户价值排行` 页面,支持按净收入/支付金额/支付笔数等多维度排序,支持导出 Excel,点击可跳转查看该用户的订单明细
|
||||||
|
- 【新增】`vk-stat-result` 统计结果表
|
||||||
|
- 【新增】定时任务 `statUser`(每小时执行用户统计)、`clearExpiredCache`(每小时清理 vk-global-data 过期缓存)
|
||||||
|
- 【调整】`支付订单明细` 页面,订单列表和详情弹窗从 `pages_plugs/system_uni/vk-pay-orders` 迁移至 `pages/vk-stats/pay`,详情弹窗 UI 全面重构(顶部概要卡片 + 基础信息/通知回调/退款信息三 Tab + 订单时间轴)
|
||||||
|
- 【调整】 `云端错误统计` 页面,从 `pages_plugs/system_uni/vk-error-log` 迁移至 `pages/vk-stats/error`,支持按状态筛选和处理操作
|
||||||
|
- 【调整】`登录日志` 页面,从 `pages_plugs/system_uni/uni-id-log` 迁移至 `pages/vk-stats/user`,支持按应用、IP、设备、用户等多维度筛选
|
||||||
|
- 【调整】云函数定时任务超时时间从 900 秒(15 分钟)提升至 7200 秒(2 小时)
|
||||||
|
|
||||||
|
|
||||||
|
##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html)
|
||||||
Reference in New Issue
Block a user