上传文件至「/」
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