build: trident-sync prepare

This commit is contained in:
xiaojunnuo
2023-01-29 13:44:19 +08:00
parent dcd1023a39
commit 07a45b4530
589 changed files with 36886 additions and 2 deletions
@@ -0,0 +1,225 @@
import { request, requestForMock } from "/src/api/service";
import "/src/mock";
import UiAntdv from "@fast-crud/ui-antdv";
import { FastCrud, UseCrudProps, useTypes, setLogger } from "@fast-crud/fast-crud";
import "@fast-crud/fast-crud/dist/style.css";
import { FsExtendsUploader, FsExtendsEditor, FsExtendsJson, FsExtendsCopyable, FsExtendsTime } from "@fast-crud/fast-extends";
import "@fast-crud/fast-extends/dist/style.css";
import { useCrudPermission } from "../permission";
function install(app, options: any = {}) {
app.use(UiAntdv);
//设置日志级别
setLogger({ level: "debug" });
app.use(FastCrud, {
i18n: options.i18n,
async dictRequest({ url }) {
if (url && url.startsWith("/mock")) {
//如果是crud开头的dict请求视为mock
return await requestForMock({ url, method: "post" });
}
return await request({ url, method: "post" });
},
/**
* useCrud时会被执行
* @param contextuseCrud的参数
*/
commonOptions(context: UseCrudProps) {
const crudBinding = context.expose?.crudBinding;
const opts = {
table: {
size: "small",
pagination: false,
onResizeColumn: (w, col) => {
crudBinding.value.table.columnsMap[col.key].width = w;
}
},
rowHandle: {
buttons: {
view: { type: "link", text: null, icon: "ion:eye-outline" },
edit: { type: "link", text: null, icon: "ion:create-outline" },
remove: { type: "link", style: { color: "red" }, text: null, icon: "ion:trash-outline" }
},
dropdown: {
more: {
type: "link"
}
}
},
request: {
transformQuery: ({ page, form, sort }) => {
const limit = page.pageSize;
const currentPage = page.currentPage ?? 1;
const offset = limit * (currentPage - 1);
sort = sort == null ? {} : sort;
return {
page: {
limit,
offset
},
query: form,
sort
};
},
transformRes: ({ res }) => {
const pageSize = res.limit;
let currentPage = res.offset / pageSize;
if (res.offset % pageSize === 0) {
currentPage++;
}
return { currentPage, pageSize, ...res };
}
},
form: {
display: "flex",
labelCol: {
//固定label宽度
span: null,
style: {
width: "120px"
}
},
wrapperCol: {
span: null
}
}
};
// 从 useCrud({permission}) 里获取permission参数,去设置各个按钮的权限
const crudPermission = useCrudPermission({ permission: context.permission });
return crudPermission.merge(opts);
}
});
// fast-extends里面的扩展组件均为异步组件,只有在使用时才会被加载,并不会影响首页加载速度
//安装uploader 公共参数
app.use(FsExtendsUploader, {
defaultType: "cos",
cos: {
domain: "https://d2p-demo-1251260344.cos.ap-guangzhou.myqcloud.com",
bucket: "d2p-demo-1251260344",
region: "ap-guangzhou",
secretId: "", //
secretKey: "", // 传了secretKey 和secretId 代表使用本地签名模式(不安全,生产环境不推荐)
getAuthorization(custom) {
// 不传secretKey代表使用临时签名模式,此时此参数必传(安全,生产环境推荐)
return request({
url: "http://www.docmirror.cn:7070/api/upload/cos/getAuthorization",
method: "get"
}).then((ret) => {
// 返回结构如下
// ret.data:{
// TmpSecretId,
// TmpSecretKey,
// XCosSecurityToken,
// ExpiredTime, // SDK 在 ExpiredTime 时间前,不会再次调用 getAuthorization
// }
return ret;
});
},
successHandle(ret) {
// 上传完成后可以在此处处理结果,修改url什么的
console.log("success handle:", ret);
return ret;
}
},
alioss: {
domain: "https://d2p-demo.oss-cn-shenzhen.aliyuncs.com",
bucket: "d2p-demo",
region: "oss-cn-shenzhen",
accessKeyId: "",
accessKeySecret: "",
async getAuthorization(custom, context) {
// 不传accessKeySecret代表使用临时签名模式,此时此参数必传(安全,生产环境推荐)
const ret = await request({
url: "http://www.docmirror.cn:7070/api/upload/alioss/getAuthorization",
method: "get"
});
console.log("ret", ret);
return ret;
},
sdkOpts: {
// sdk配置
secure: true // 默认为非https上传,为了安全,设置为true
},
successHandle(ret) {
// 上传完成后可以在此处处理结果,修改url什么的
console.log("success handle:", ret);
return ret;
}
},
qiniu: {
bucket: "d2p-demo",
async getToken(options) {
const ret = await request({
url: "http://www.docmirror.cn:7070/api/upload/qiniu/getToken",
method: "get"
});
return ret; // {token:xxx,expires:xxx}
},
successHandle(ret) {
// 上传完成后可以在此处处理结果,修改url什么的
console.log("success handle:", ret);
return ret;
},
domain: "http://d2p.file.handsfree.work/"
},
form: {
action: "http://www.docmirror.cn:7070/api/upload/form/upload",
name: "file",
withCredentials: false,
uploadRequest: async ({ action, file, onProgress }) => {
// @ts-ignore
const data = new FormData();
data.append("file", file);
return await request({
url: action,
method: "post",
headers: {
"Content-Type": "multipart/form-data"
},
timeout: 60000,
data,
onUploadProgress: (p) => {
onProgress({ percent: Math.round((p.loaded / p.total) * 100) });
}
});
},
successHandle(ret) {
// 上传完成后的结果处理, 此处应返回格式为{url:xxx}
return {
url: "http://www.docmirror.cn:7070" + ret,
key: ret.replace("/api/upload/form/download?key=", "")
};
}
}
});
//安装editor
app.use(FsExtendsEditor, {
//编辑器的公共配置
wangEditor: {}
});
app.use(FsExtendsJson);
app.use(FsExtendsTime);
app.use(FsExtendsCopyable);
const { addTypes } = useTypes();
addTypes({
time2: {
//如果与官方字段类型同名,将会覆盖官方的字段类型
form: { component: { name: "a-date-picker" } },
column: { component: { name: "fs-date-format", format: "YYYY-MM-DD" } },
valueBuilder(context) {
console.log("time2,valueBuilder", context);
}
}
});
}
export default {
install
};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import "./iconfont.js"
@@ -0,0 +1,2 @@
// import "@iconify/iconify";
import "@purge-icons/generated";
@@ -0,0 +1,12 @@
import "./iconify";
import "./iconfont";
import FastCrud from "./fast-crud";
import permission from "./permission";
function install(app, options: any = {}) {
app.use(FastCrud, options);
app.use(permission);
}
export default {
install
};
@@ -0,0 +1,10 @@
import { request } from "/src/api/service";
export async function getPermissions() {
const ret = await request({
url: "/sys/authority/user/permissions",
method: "post"
});
// 如果使用你自己的后端,需要在此处将返回结果改造为本模块需要的结构
// 结构详情,请参考示例中打印的日志 ”获取权限数据成功:{...}“ (实际上就是“资源管理”页面中列出来的数据)
return ret;
}
@@ -0,0 +1,9 @@
import permission from "./permission";
import permissionUtil from "../util.permission";
const install = function (app) {
app.directive("permission", permission);
app.config.globalProperties.$hasPermissions = permissionUtil.hasPermissions;
};
permission.install = install;
export default permission;
@@ -0,0 +1,11 @@
import permissionUtil from "../util.permission";
export default {
mounted(el, binding, vnode) {
const { value } = binding;
const hasPermission = permissionUtil.hasPermissions(value);
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el);
}
}
};
@@ -0,0 +1,5 @@
export class NoPermissionError extends Error {
constructor(message?: string) {
super(message || "对不起,您没有权限执行此操作");
}
}
@@ -0,0 +1,45 @@
import router from "/src/router";
import { useUserStore } from "/@/store/modules/user";
import { usePermissionStore } from "./store.permission";
import util from "./util.permission";
import { message } from "ant-design-vue";
import NProgress from "nprogress";
export function registerRouterHook() {
// 注册路由beforeEach钩子,在第一次加载路由页面时,加载权限
router.beforeEach(async (to, from, next) => {
const permissionStore = usePermissionStore();
if (permissionStore.isInited) {
if (to.meta.permission) {
//校验权限
// @ts-ignore
if (!util.hasPermissions(to.meta.permission)) {
//没有权限
message.warn("对不起,您没有权限");
//throw new Error("对不起,您没有权限");
NProgress.done();
return false;
}
}
next();
return;
}
const userStore = useUserStore();
const token = userStore.getToken;
if (!token || token === "undefined") {
next();
return;
}
// 初始化权限列表
try {
console.log("permission is enabled");
await permissionStore.loadFromRemote();
console.log("PM load success");
next({ ...to, replace: true });
} catch (e) {
console.error("加载动态路由失败", e);
next();
}
});
}
@@ -0,0 +1,23 @@
import permissionDirective from "./directive/index";
import { registerRouterHook } from "./hook";
import util from "./util.permission";
export * from "./use-crud-permission";
export * from "./errors";
export function usePermission() {
return {
...util
};
}
export default {
install(app) {
// 开启权限模块
// 注册v-permission指令, 用于控制按钮权限
app.use(permissionDirective);
// 注册路由钩子
// 通过路由守卫,在登录成功后拦截路由,从后台加载权限数据
// 然后将权限数据转化为菜单和路由,添加到系统中
registerRouterHook();
}
};
@@ -0,0 +1,89 @@
import { defineStore } from "pinia";
import { useResourceStore } from "/src/store/modules/resource";
import { getPermissions } from "./api";
import { mitter } from "/@/utils/util.mitt";
import { env } from "/@/utils/util.env";
//监听注销事件
mitter.on("app.logout", () => {
const permissionStore = usePermissionStore();
permissionStore.clear();
});
interface PermissionState {
permissions: [];
inited: boolean;
}
/**
* 构建权限码列表
* @param menuTree
* @param permissionList
* @returns {*}
*/
function formatPermissions(menuTree: Array<any>, permissionList = []) {
if (menuTree == null) {
menuTree = [];
}
menuTree.forEach((item: any) => {
if (item.permission) {
// @ts-ignore
permissionList.push(item.permission);
}
if (item.children != null && item.children.length > 0) {
formatPermissions(item.children, permissionList);
}
});
return permissionList;
}
export const usePermissionStore = defineStore({
id: "app.permission",
state: (): PermissionState => ({
permissions: [],
inited: false
}),
getters: {
getPermissions() {
// @ts-ignore
return this.permissions;
},
isInited() {
// @ts-ignore
return this.inited;
}
},
actions: {
init({ permissions }) {
this.permissions = permissions;
this.inited = true;
},
clear() {
this.permissions = [];
this.inited = false;
},
resolve(resourceTree) {
const permissions = formatPermissions(resourceTree);
this.init({ permissions });
//过滤没有权限的菜单
const resourceStore = useResourceStore();
resourceStore.filterByPermission(permissions);
},
async loadFromRemote() {
let permissionTree = [];
if (env.PM_ENABLED === "false") {
console.warn("当前权限模块未开启,权限列表为空");
} else {
//开启了权限模块,向后台请求权限列表
const data = await getPermissions();
if (data != null) {
permissionTree = data;
} else {
console.warn("当前获取到的权限列表为空");
}
}
this.resolve(permissionTree);
}
}
});
@@ -0,0 +1,60 @@
import { usePermission } from "/@/plugin/permission";
import _ from "lodash-es";
/**
* 设置按钮动作权限
* @param permission {prefix,extra}
*/
export function useCrudPermission({ permission }) {
const { hasPermissions } = usePermission();
const prefix = permission instanceof Object ? permission.prefix : permission;
//根据权限显示按钮
function hasActionPermission(action) {
if (!prefix) {
return true;
}
return hasPermissions(prefix + ":" + action);
}
function buildCrudPermission() {
if (permission == null) {
return {};
}
let extra = {};
if (permission instanceof Object) {
extra = permission.extra;
if (permission.extra && permission.extra instanceof Function) {
extra = permission.extra({ hasActionPermission });
}
}
return _.merge(
{
actionbar: {
buttons: {
add: { show: hasActionPermission("add") }
}
},
rowHandle: {
buttons: {
edit: { show: hasActionPermission("edit") },
remove: { show: hasActionPermission("remove") },
view: { show: hasActionPermission("view") }
}
}
},
extra
);
}
function merge(userOptions) {
const permissionOptions = buildCrudPermission();
_.merge(permissionOptions, userOptions);
return permissionOptions;
}
return { merge, buildCrudPermission, hasActionPermission };
}
@@ -0,0 +1,29 @@
import { usePermissionStore } from "./store.permission";
import { NoPermissionError } from "./errors";
import { message } from "ant-design-vue";
const util = {
hasPermissions: (value: string | string[]): boolean => {
let need: string[] = [];
if (typeof value === "string") {
need.push(value);
} else if (value && value instanceof Array && value.length > 0) {
need = need.concat(value);
}
if (need.length === 0) {
throw new Error('need permissions! Like "sys:user:view" ');
}
const permissionStore = usePermissionStore();
const userPermissionList = permissionStore.getPermissions;
return userPermissionList.some((permission) => {
return need.includes(permission);
});
},
requirePermissions: (value) => {
if (!util.hasPermissions(value)) {
message.error("对不起,您没有权限执行此操作");
throw new NoPermissionError();
}
}
};
export default util;