first commit

This commit is contained in:
编码猿
2024-09-27 00:48:07 +08:00
commit 342c8c1b1b
95 changed files with 23969 additions and 0 deletions

1
src/core/.pydio Normal file
View File

@@ -0,0 +1 @@
d7cca889-05d9-4311-b88d-a72968fc4581

View File

@@ -0,0 +1 @@
c2c6ec3b-b4b9-42f4-92b0-4e10d1e027a6

View File

@@ -0,0 +1 @@
cbff3cfc-8ebf-4480-a698-e4a7c6040408

View File

@@ -0,0 +1,103 @@
import { setStore } from './store';
import { StoreItemType, StoreItemOptions } from './typing';
export function serialize(serializer: StoreItemType['serializer'], disallowIgnore = false) {
return (target: any, propertyKey: string) => {
setStore(target, {
key: propertyKey,
serializer,
disallowIgnoreSerializer: disallowIgnore,
});
};
}
export function deserialize(deserializer: StoreItemType['deserializer'], disallowIgnore = false) {
return (target: any, propertyKey: string) => {
setStore(target, {
key: propertyKey,
deserializer,
disallowIgnoreDeserializer: disallowIgnore,
});
};
}
export function beforeDeserialize(beforeDeserializer: StoreItemType['beforeDeserializer'], disallowIgnore = false) {
return (target: any, propertyKey: string) => {
setStore(target, {
key: propertyKey,
beforeDeserializer,
disallowIgnoreBeforeDeserializer: disallowIgnore,
});
};
}
export function afterSerialize(afterSerializer: StoreItemType['afterSerializer'], disallowIgnore = false) {
return (target: any, propertyKey: string) => {
setStore(target, {
key: propertyKey,
afterSerializer,
disallowIgnoreAfterSerializer: disallowIgnore,
});
};
}
export function serializeTarget() {
return (target: any, propertyKey: string) => {
setStore(target, {
key: propertyKey,
serializeTarget: true,
});
};
}
export function property(originalKey?: string, targetClass?: StoreItemType['targetClass'], isOptional = false) {
return (target: any, propertyKey: string) => {
// propertyKey 使用装饰器的 属性 名称,例如:id
// originalKey json 数据的 key,例如: { i: 1, name: 123 } 中的 i
// console.log("property target: ", target);
// console.log("property propertyKey: ", propertyKey);
// console.log("property originalKey: ", originalKey);
const config: StoreItemOptions = {
originalKey: originalKey || propertyKey,
key: propertyKey,
};
if (targetClass) {
config.targetClass = targetClass.prototype.constructor;
// console.log("有 targetClass ...");
// console.log("config: ",config.targetClass);
}
if (isOptional) {
config.optional = isOptional;
}
setStore(target, config);
};
}
export function typed(targetClass: StoreItemType['targetClass']) {
return (target: any, propertyKey: string) => {
setStore(target, {
key: propertyKey,
targetClass,
});
};
}
export function optional() {
return (target: any, propertyKey: string) => {
setStore(target, {
key: propertyKey,
optional: true,
});
};
}
export function defaultValue(value: any) {
return (target: any, propertyKey: string) => {
setStore(target, {
key: propertyKey,
default: value,
});
};
}

View File

@@ -0,0 +1,4 @@
export * from './to-class';
export * from './to-plain';
export * from './decorators';
export * from './typing';

View File

@@ -0,0 +1,27 @@
// @ts-nocheck
import { StoreItemOptions, StoreItemType } from './typing';
const store = new Map<Function, Map<string, StoreItemType>>();
export const originalKeyStores = new Map<Function, Map<string, StoreItemOptions[]>>();
export const keyStores = new Map<Function, Map<string, StoreItemType>>();
export const setStore = (target: Function, options: StoreItemOptions) => {
const { key, ...rest } = options;
// 获取被装饰 属性 所在类的 构造函数,作为存储 Map 的 key
const storeKey = target.constructor;
// 判断是否已经存储过,如果已经存在 get 获取之前存在的 key 对应的数值,不存在 创建新的 map
const targetStore = store.has(storeKey) ? store.get(storeKey) : new Map<string, StoreItemType>();
// 判断被装饰的 属性(id,name)是否已经存在, 存在 获取 key 对应 的 StoreItemType,不存在为 {}
let value = targetStore.has(key) ? targetStore.get(key) : {};
value = {
...value,
...rest,
};
targetStore.set(key, value);
store.set(storeKey, targetStore);
};
export default store;

View File

@@ -0,0 +1,79 @@
import isArray from 'isarray';
import { getOriginalKeyStore, isUndefined, isNullOrUndefined } from './utils';
import { JosnType, StoreItemOptions, BasicClass, ToClassOptions } from './typing';
export const arrayItemToClass = <T>(arrayVal: any[], Clazz: BasicClass<T>, options: ToClassOptions): any => {
return arrayVal.map((v: any) =>
// eslint-disable-next-line @typescript-eslint/no-use-before-define
isArray(v) ? arrayItemToClass(v, Clazz, options) : objectToClass(v, Clazz, options),
);
};
/**
*
* @param jsonObj json 数据
* @param Clazz 传入类的 构造函数
* @param options
* @returns
*/
const objectToClass = <T>(jsonObj: Record<string, any>, Clazz: BasicClass<T>, options: ToClassOptions): T => {
// 初始化 传入的类
const instance: any = new Clazz();
const originalKeyStore = getOriginalKeyStore(Clazz);
originalKeyStore.forEach((propertiesOptions: StoreItemOptions[], originalKey) => {
const originalValue = jsonObj[originalKey];
propertiesOptions.forEach((storeItemoptions: StoreItemOptions) => {
// console.log("propertiesOptions storeItemoptions: ", storeItemoptions);
const { key, beforeDeserializer, deserializer, targetClass, optional } = storeItemoptions;
const disallowIgnoreDeserializer = storeItemoptions.disallowIgnoreDeserializer || !options.ignoreDeserializer;
const disallowIgnoreBeforeDeserializer =
storeItemoptions.disallowIgnoreBeforeDeserializer || !options.ignoreBeforeDeserializer;
const isValueNotExist = options.distinguishNullAndUndefined ? isUndefined : isNullOrUndefined;
let value = originalValue;
if (isValueNotExist(value)) {
if (!isValueNotExist(storeItemoptions.default)) {
instance[key] = storeItemoptions.default;
return;
}
if (!optional) {
throw new Error(`Can't map '${originalKey}' to ${Clazz.name}.${key}, property '${originalKey}' not found`);
}
return;
}
value =
beforeDeserializer && disallowIgnoreBeforeDeserializer
? beforeDeserializer(value, instance, jsonObj, options)
: value;
if (value && targetClass) {
if (isArray(value)) {
value = arrayItemToClass(value, targetClass, options);
} else {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
value = toClass(value, targetClass, options);
}
}
instance[key] =
deserializer && disallowIgnoreDeserializer ? deserializer(value, instance, jsonObj, options) : value;
});
});
return instance;
};
export const toClasses = <T>(rawJson: JosnType[], Clazz: BasicClass<T>, options: ToClassOptions = {}): T[] => {
if (!isArray(rawJson)) {
throw new Error(`rawJson ${rawJson} must be an array`);
}
const { constructor } = Clazz.prototype;
return rawJson.map((item: object) => objectToClass<T>(item, constructor, options));
};
export const toClass = <T>(rawJson: JosnType, Clazz: BasicClass<T>, options: ToClassOptions = {}): T => {
const { constructor } = Clazz.prototype;
return objectToClass<T>(rawJson as object, constructor, options);
};
export const JsontoClass = toClass
export const JsontoClasses = toClasses

View File

@@ -0,0 +1,55 @@
// @ts-nocheck
import isArray from 'isarray';
import { getKeyStore, isUndefined, isNullOrUndefined } from './utils';
import { JosnType, BasicClass, StoreItemType, ToPlainOptions } from './typing';
export const arrayItemToObject = <T>(arrayVal: any[], Clazz: BasicClass<T>, options: ToPlainOptions): any => {
return arrayVal.map((v: any) =>
// eslint-disable-next-line @typescript-eslint/no-use-before-define
isArray(v) ? arrayItemToObject(v, Clazz, options) : classToObject(v, Clazz, options),
);
};
const classToObject = <T>(instance: JosnType, Clazz: BasicClass<T>, options: ToPlainOptions): JosnType => {
const obj: JosnType = {};
const keyStore = getKeyStore(Clazz);
keyStore.forEach((propertiesOption: StoreItemType, key: keyof JosnType) => {
const isValueNotExist = options.distinguishNullAndUndefined ? isUndefined : isNullOrUndefined;
const instanceValue = isValueNotExist(instance[key]) ? propertiesOption.default : instance[key];
const { originalKey, afterSerializer, serializer, targetClass, optional } = propertiesOption;
const disallowIgnoreSerializer = propertiesOption.disallowIgnoreSerializer || !options.ignoreSerializer;
const disallowIgnoreAfterSerializer =
propertiesOption.disallowIgnoreAfterSerializer || !options.ignoreAfterSerializer;
if (isValueNotExist(instanceValue)) {
if (!optional) {
throw new Error(`Property '${Clazz.name}.${key}' not found`);
}
return;
}
let value =
serializer && disallowIgnoreSerializer ? serializer(instanceValue, instance, obj, options) : instanceValue;
if (value && targetClass) {
if (isArray(value)) {
value = arrayItemToObject(value, targetClass, options);
} else {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
value = toPlain(value, targetClass, options);
}
}
obj[originalKey] =
afterSerializer && disallowIgnoreAfterSerializer ? afterSerializer(value, instance, obj, options) : value;
});
return obj;
};
export const toPlains = <T>(instances: (T | JosnType)[], Clazz: BasicClass<T>, options: ToPlainOptions = {}): any[] => {
if (!isArray(instances)) {
throw new Error(`${Clazz} instances must be an array`);
}
return instances.map((item: JosnType) => classToObject<T>(item, Clazz, options));
};
export const toPlain = <T>(instance: T | JosnType, Clazz: BasicClass<T>, options: ToPlainOptions = {}): any => {
return classToObject<T>(instance, Clazz, options);
};

View File

@@ -0,0 +1,38 @@
export type StoreItemType = {
originalKey?: string;
targetClass?: BasicClass;
serializer?: (value: any, instance: any, origin: any, options: ToPlainOptions) => any;
disallowIgnoreSerializer?: boolean;
afterSerializer?: (value: any, instance: any, origin: any, options: ToPlainOptions) => any;
disallowIgnoreAfterSerializer?: boolean;
deserializer?: (value: any, instance: any, origin: any, options: ToClassOptions) => any;
disallowIgnoreDeserializer?: boolean;
beforeDeserializer?: (value: any, instance: any, origin: any, options: ToClassOptions) => any;
disallowIgnoreBeforeDeserializer?: boolean;
default?: any;
autoTypeDetection?: boolean;
optional?: boolean;
serializeTarget?: boolean;
};
export type StoreItemOptions = StoreItemType & {
key: string;
};
export type BasicClass<T = any> = {
new (...args: any[]): T;
};
export type JosnType = { [key: string]: any };
export interface ToClassOptions {
ignoreDeserializer?: boolean;
ignoreBeforeDeserializer?: boolean;
distinguishNullAndUndefined?: boolean;
}
export interface ToPlainOptions {
ignoreSerializer?: boolean;
ignoreAfterSerializer?: boolean;
distinguishNullAndUndefined?: boolean;
}

View File

@@ -0,0 +1,78 @@
// @ts-nocheck
import { StoreItemOptions, StoreItemType, BasicClass } from './typing';
import store, { keyStores, originalKeyStores } from './store';
export const isNull = (val: any) => val === null;
export const isUndefined = (val: any) => val === undefined;
export const isNullOrUndefined = (val: any) => isNull(val) || isUndefined(val);
export const getOriginalKeyStore = <T>(Clazz: BasicClass<T>) => {
let curLayer = Clazz;
const cacheOriginalKeyStore = originalKeyStores.get(curLayer);
// console.log("cacheOriginalKeyStore: ", cacheOriginalKeyStore);
if (cacheOriginalKeyStore) {
return cacheOriginalKeyStore;
}
const originalKeyStore = new Map<string, StoreItemOptions[]>();
while (curLayer.name && curLayer.prototype) {
const { constructor } = curLayer.prototype;
const targetStore = store.get(constructor);
// console.log("targetStore: ", targetStore);
if (targetStore) {
targetStore.forEach((storeItem, key) => {
const item = {
key,
...storeItem,
};
// console.log("item: ", item);
if (!originalKeyStore.has(storeItem.originalKey)) {
originalKeyStore.set(storeItem.originalKey, [item]);
} else {
const exists = originalKeyStore.get(storeItem.originalKey);
if (!exists.find((exist: StoreItemOptions) => exist.key === key)) {
originalKeyStore.set(storeItem.originalKey, [...originalKeyStore.get(storeItem.originalKey), item]);
}
}
});
}
curLayer = Object.getPrototypeOf(constructor);
}
originalKeyStores.set(Clazz, originalKeyStore);
return originalKeyStore;
};
export const getKeyStore = <T>(Clazz: BasicClass<T>) => {
const cacheKeyStore = keyStores.get(Clazz);
if (cacheKeyStore) {
return cacheKeyStore;
}
const keyStore = new Map<string, StoreItemType>();
const originalKeyStore = getOriginalKeyStore(Clazz);
originalKeyStore.forEach(storeItems => {
const [firstStoreItem] = storeItems;
if (storeItems.length === 1) {
keyStore.set(firstStoreItem.key, firstStoreItem);
} else {
const hasStoreItems = storeItems.filter(storeItem => storeItem.serializeTarget);
if (hasStoreItems.length !== 1) {
throw new Error(
`Only one of keys(${storeItems.map(storeItem => storeItem.key).join(', ')}) in ${
Clazz.name
} can contain a serializeTarget when use toPlain`,
);
}
const hasStoreItem = hasStoreItems[0];
keyStore.set(hasStoreItem.key, hasStoreItem);
}
});
keyStores.set(Clazz, keyStore);
return keyStore;
};

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2023. bmy
* Email:2271608011@qq.com
* Github:https://github.com/helpcode
*/
import { ConfigureConfig } from "@config/configure.config";
import AxioDao from "@dao/index.dao";
import { JsontoClass, JsontoClasses } from "@ann/JsonToClass";
interface ParamsType {
url?: string;
useHandle?: boolean;
header?: { [key: string]: any };
}
/**
* 将 接口返回 数据所对应的 类,在类的方法上定义元数据,key为mapper,值为 传入的 type
* @param type
* @returns
*/
export function Mapper(type: { new(...args: any[]): any }) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
Reflect.defineMetadata('mapper', type, target, propertyKey);
}
}
/**
* GET 请求注解
* @param RequestParams
* @constructor
*/
export function GET(RequestParams?: ParamsType) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
CheckParams('get', target, propertyKey, descriptor, <ParamsType>RequestParams)
}
}
/**
* POST 请求注解
* @param RequestParams
* @constructor
*/
export function POST(RequestParams?: ParamsType) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
CheckParams('post', target, propertyKey, descriptor, <ParamsType>RequestParams)
}
}
/**
* PUT 请求注解
* @param RequestParams
* @constructor
*/
export function PUT(RequestParams?: ParamsType) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
CheckParams('put', target, propertyKey, descriptor, <ParamsType>RequestParams)
}
}
/**
* DELETE 请求注解
* @param RequestParams
* @constructor
*/
export function DELETE(RequestParams?: ParamsType) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
CheckParams('delete', target, propertyKey, descriptor, <ParamsType>RequestParams)
}
}
// GET POST PUT DELETE 四个装饰器最终 都会走这里代码进行发送请求
// 所以 在 http.annotation.ts 文件中 引入插件 json-class-interface
// 调 json-class-interface 的方法 来配置 生成的 class 存放路径 为 /service/type 文件夹
// 请求完成后 先使用 装饰器 的 target.name+_+propertyKey 作为文件名并 在路径下生成空的 .ts 文件
// 然后调用 json-class-interface 的 toClass 方法传入propertyKey作为第一层类的名称
// 并传入 res 请求到的json数据,得到最终的 类代码,然后让 json-class-interface 将 类代码 写入刚生成的 .ts 文件中
// 唯一需要开发者手动做的事情如下,举例:
// User.service.impl.ts 中 的 xxx 方法 GET 装饰器 传入 刚生成文件中的 propertyKey 类名
// 这里的代码会自动调用 插件 json-mapper-class 进行 JsontoClasses 或者 JsontoClass 进行序列化
// 伪代码
// configTypePath("service/type")
// wirteFileType(`${target.name_propertyKey}.ts`, toClass(propertyKey,res) )
//
function CheckParams(
methods: "get" | "post" | "put" | "delete",
target: any, propertyKey: string,
descriptor: PropertyDescriptor,
Params: ParamsType) {
Params == undefined ? Params = {} : null;
Params.url = Params.url || ConfigureConfig.AjaxConfig.ApiList[propertyKey]
Params.useHandle = Params.useHandle || false
Params.header = Params.header || {}
let MapperClass = Reflect.getMetadata('mapper', target, propertyKey);
if (MapperClass) {
let OldMethods = descriptor.value;
descriptor.value = async (data: { [key: string]: any }) => {
let res = await AxioDao[methods]({
url: <string>Params.url, data,
headers: Params.header
});
res = res instanceof Array ? JsontoClasses(res, MapperClass) : JsontoClass(res, MapperClass)
if (Params.useHandle) {
return await OldMethods.call(target, res)
} else {
return res
}
}
}
}

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) 2020. bmy
*/
export function Autowired(params?: any) {
return (target: any, propertyKey: string) => {
let typeClass = Reflect.getMetadata('design:type', target, propertyKey);
Object.defineProperty(target, propertyKey, {
value: params ? new typeClass(new params) : new typeClass(),
writable: true,
configurable: true
});
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2020. bmy
*/
import Vue from 'vue';
import { ConfigureConfig } from "@config/configure.config";
import { CreateElement } from 'vue/types/umd';
import Es6Promise from 'es6-promise'
Es6Promise.polyfill()
export function Start<T extends { new ( ...args: any[] ): { } }>( _ : T ) : T {
// @ts-ignore
return class extends _ {
constructor() {
super();
(new Vue({
// @ts-ignore
router: this.Router, store: this.VueX, render: (h: CreateElement) => h(this.app)
}) as Vue).$mount('#app')
}
}
}
export function RegServiceAndMethods(constructor: { new(...args: any[]): {}; }) {
// newInstance(require.context("../service/impl", false, /\.ts$/))
newInstance(require.context("../utils", false, /\.ts$/))
}
function newInstance(context: __WebpackModuleApi.RequireContext) {
context.keys().forEach((key: any) => {
let m = context(key), className: string = Object.keys(m)[0];
new m[className]()
});
}
/**
* 自动注册Vue插件
* @constructor
*/
export function RegVuePlugs(constructor: { new(...args: any[]): {}; }) {
ConfigureConfig.VuePlugs.forEach((v: any) => Vue.use(v))
}
/**
* 自动挂载Vue 全局方法
* @constructor
*/
export function GlobalMethod(target: any, propertyKey: string) {
Vue.prototype[`$${ propertyKey }`] = target[propertyKey]
}

1
src/core/config/.pydio Normal file
View File

@@ -0,0 +1 @@
f0ed9e16-3f2b-4d50-9858-120dc2e2ae2c

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2020. bmy
* Email:2271608011@qq.com
* Github:https://github.com/helpcode
*/
import VueRouter, { RouterOptions } from 'vue-router';
import Vuex from 'vuex';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
import { AutoRoutesConfig } from "@config/route.config";
import { PluginObject } from "vue";
export class ConfigureConfig {
/**
* 接口配置: 测试环境基地址,正式环境基地址,具体页面接口
*/
public static AjaxConfig: {
DevUrl: string,
ProdUrl: string,
ApiList: { [key: string]: string }
} = {
DevUrl: 'http://127.0.0.1:8080',
ProdUrl: 'http://127.0.0.1:9090/api',
ApiList: {
// start - 注释内的key都将被Node.js监听并diff取出实时编辑后的差异项,然后程序决定是否增删请求中间层xx文件中的xx方法代码【不要删除】
UserList: '/UserList',
// User_IndexTest: '/test',
// Car_carList: '/test',
// Car_addCar: '/test',
// Index_reg: '/reg',
// Order_test: '/test',
// end - 注释内的key都将被Node.js监听并diff取出实时编辑后的差异项,然后程序决定是否增删请求中间层xx文件中的xx方法代码【不要删除】
}
};
/**
* Vue 插件
*/
public static VuePlugs: PluginObject<never>[] = [
VueRouter, Vuex, Antd
];
/**
* 路由配置
*/
public static RouterConfigUrl: RouterOptions = {
mode: 'hash',
base: './',
routes: AutoRoutesConfig
};
}

View File

@@ -0,0 +1,18 @@
// 根据page目录结构,自动生成的路由配置文件
// 参考Nuxt.js 源码,同时自己 + ast 实现 https://zh.nuxtjs.org/guide/routing
// @ts-ignore
export const AutoRoutesConfig = [
{
name: "About",
path: "/About",
component: () => import(/* webpackChunkName: 'About' */ '@page/about'),
meta: { title: '关于我页面', showNav: true, isLogin: true }
},
{
name: "Home",
path: "/Home",
component: () => import(/* webpackChunkName: 'Home' */ '@page/home'),
meta: { title: '首页', showNav: true, isLogin: true }
}
];

1
src/core/dao/.pydio Normal file
View File

@@ -0,0 +1 @@
852dea68-05ee-4958-8884-27c503363732

98
src/core/dao/index.dao.ts Normal file
View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2020. bmy
*/
import axios, { AxiosInstance, AxiosError, AxiosRequestConfig } from "axios";
import { IndexUtils } from "@utils/index.utils";
/**
* axios的封装
*/
export class AxioDao {
instance: AxiosInstance;
public constructor() {
this.instance = axios.create({
baseURL: IndexUtils.CheckAjaxUrl(),
timeout: 10000,
headers: {
"Content-Type": "application/json"
}
});
this.ResponseInterceptor();
this.RequestInterceptor();
}
public async get(params: AxiosRequestConfig): Promise<any> {
return await this.instance.get(<string>params.url, {
params: params.data,
headers: Object.assign({ Authorization: localStorage.getItem("token") }, params.headers)
});
}
public async post(params: AxiosRequestConfig): Promise<any> {
return await this.instance.post(<string>params.url, params.data, {
headers: Object.assign({ Authorization: localStorage.getItem("token") }, params.headers)
})
}
/**
* Put 请求
* 请求参数请参考接口:RequestParams
* @param params
*/
public async put(params: AxiosRequestConfig): Promise<any> {
return await this.instance.put(<string>params.url, params.data)
}
/**
* delete 请求
* 请求参数请参考接口:RequestParams
* @param params
*/
public async delete(params: AxiosRequestConfig): Promise<any> {
return await this.instance.delete(<string>params.url, { params: params.data })
}
/**
* 响应拦截器
* @constructor
*/
public async ResponseInterceptor(): Promise<any> {
this.instance.interceptors.response.use(
(response: any) => {
return response.data.result;
},
(error: AxiosError) => {
console.log(`
❌ 请求错误 ❌
1、基地址: ${error.config.baseURL}
2、短地址: ${error.config.url}
3、请求 方式: ${error.config.method}
4、请求 参数: ${JSON.stringify(error.config.params)}
5、请求 头 : ${JSON.stringify(error.config.headers)}
------------------------------------------------------------
6、错误信息为: ${error.message}
7、错误代码为: ${error.stack}
`);
return Promise.reject(error)
})
}
/**
* 添加请求拦截器
* @constructor
*/
public async RequestInterceptor(): Promise<any> {
this.instance.interceptors.request.use((config: any) => {
return config
}, function (error: AxiosError) {
return Promise.reject(error)
})
}
}
export default new AxioDao();

1
src/core/run/.pydio Normal file
View File

@@ -0,0 +1 @@
45df40b6-06b8-4b49-9ece-3df4b113d74f

51
src/core/run/init.run.ts Normal file
View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2020. bmy
*/
import 'reflect-metadata';
import 'babel-polyfill'
// import '@types/RouterHooks';
import Vue, { VueConstructor, Component } from 'vue';
import App from '@application/app'
import { ConfigureConfig } from "@config/configure.config";
import NavigationGuards from "@utils/navigation-guards.utils";
import VueRouter, { RawLocation, Route } from 'vue-router';
import Vuex, { Store } from 'vuex'
import StoreModeule from '@store/index'
import { RegServiceAndMethods, RegVuePlugs, Start } from "@ann/register.annotation";
import { Autowired } from "@ann/ioc.annotation";
@Start
@RegVuePlugs
@RegServiceAndMethods
export class InitRun {
@Autowired()
protected NavigationGuards!: NavigationGuards;
protected Router!: VueRouter;
protected VueX!: Store<typeof StoreModeule>;
protected app: Component = App;
constructor() {
Vue.config.productionTip = false;
this.VueRouterAndVuex()
}
private VueRouterAndVuex(): void {
this.Router = new VueRouter(ConfigureConfig.RouterConfigUrl);
// this.NavigationGuards.beforeEach(this.Router)
// this.NavigationGuards.afterEach(this.Router)
// 重写路由Push
const routerPush: (location: RawLocation) => Promise<Route> = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location: RawLocation): Promise<Route> {
// @ts-ignore
return routerPush.call(this, location).catch((error: Error) => error)
};
this.VueX = new Vuex.Store(StoreModeule)
}
}
new InitRun();

1
src/core/service/.pydio Normal file
View File

@@ -0,0 +1 @@
b6c30b87-ba50-4860-a92d-3dfe07d0ff5c

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2023. bmy
*/
import { GET, Mapper } from "@ann/http.annotation";
import { property, defaultValue, deserialize } from "@ann/JsonToClass";
// ajax接口数据返回 为 ResponseType[]
// 这里定义类,将 接口返回的数据 映射到 类中存储
export class ResponseType {
// 接口返回数据的字段 为 id,这里映射改为 user_id,代码里面用 user_id
@property("id")
@defaultValue(0)
user_id!: number;
@property("name")
@defaultValue("如果接口字段无数值,那这个参数就是默认值")
user_name!: string
}
export class UserService {
/**
* 1 提供 四个【请求装饰器】:@GET @POST @PUT @DELETE
* 参数说明:
* url 可选:接口请求短地址,如果不填默认使用 configure.config.ts 中和方法名IndexTest同名的对象key中地址
* 如果传,使用你传的地址
*
* useHandle 可选:是否需要对网络请求的结果进行修改后再返回给页面,如果需要传 true,则请求方法的入参 params 会变为ajax请求
* 得到的接口数据,处理完数据后,请 return 结果。否则 IndexTest 代码内部留空,节省大量 冗余代码!!
*
* header 可选:自定义请求头,例如文件上传等 可以在这自定义
*
* 2 @Mapper() 装饰器
* 参数说明:
* 请求方法的返回类型(必须用类来描述JSON数据类型),会被 Reflect.defineMetadata 注入 元数据,在 上一步
* 【请求装饰器】结束请求后,会从 Reflect.getMetadata 取出 元数据,然后 被 JsonToClass 使用到。
* JsonToClass 会将json数据映射到 @Mapper() 装饰器的 参数中,也就是 json数据自动存储到类属性中
*/
@GET()
@Mapper(ResponseType)
// @ts-ignore
public async UserList (params: object | ResponseType[]): Promise<ResponseType[]> {
// 留空,不要写请求代码 即可发送请求,除非 useHandle: true,这时 方法入参 params 为 ajax 接口数据,直接处理 params
// 即可,也不需要写请求代码!!
}
}

1
src/core/store/.pydio Normal file
View File

@@ -0,0 +1 @@
6dd651dd-0493-4995-a44b-c15ccfdf75a4

10
src/core/store/getters.ts Normal file
View File

@@ -0,0 +1,10 @@
/*
* Copyright (c) 2020. bmy
*/
export default {
GettersTabsContentArr: (state: any) => state.PublicConfig.TabsContentArr,
GettersTabsActive: (state: any) => state.PublicConfig.TabsActive,
GettersAsideMenu: (state: any) => state.PublicConfig.AsideMenu,
GettersIsLogin: (state: any) => state.PublicConfig.isLogin,
}

12
src/core/store/index.ts Normal file
View File

@@ -0,0 +1,12 @@
/*
* Copyright (c) 2020. bmy
*/
import index from './modules'
import getters from './getters'
// 统一导出各模块
export default {
modules: { ...index },
getters
}

View File

@@ -0,0 +1 @@
d3359e2f-bc25-4e14-b202-20080d06b04a

View File

@@ -0,0 +1,9 @@
/*
* Copyright (c) 2020. bmy
*/
import PublicConfig from './publicConfig'
export default {
PublicConfig
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2020. bmy
*/
interface state {
TabsContentArr: Array<{
title: string,
url: string,
closable: boolean,
icon: string
}>,
TabsActive: string,
isLogin: boolean,
AsideMenu: Array<{
web_href: string,
web_title: string,
icon: string,
children: Array<{
web_href: string,
web_title: string,
icon: string,
}>
}>
}
export default {
state: {
isLogin: false,
TabsContentArr: [
{ title: '系统首页', url: '/', closable: false, icon: 'el-icon-house' },
],
TabsActive: '/',
AsideMenu: [
{
web_href: '/', web_title: '系统首页', icon: 'el-icon-house',
children: []
},
{
web_href: '/System', web_title: '系统设置', icon: 'el-icon-setting',
children: [
{ web_href: '/System/MenuConfig', web_title: '菜单配置', icon: 'el-icon-tickets' },
{ web_href: '/System/wardenList', web_title: '管理员列表', icon: 'el-icon-user' },
]
},
{
web_href: '/Jurisdiction', web_title: '权限管理', icon: 'el-icon-lock',
children: [
{ web_href: '/Jurisdiction/RolePermissions', web_title: '角色权限', icon: 'el-icon-key' },
]
}
]
},
mutations: {
// 保存顶部菜单
SET_TABCONTENT: (state: state, activeMenu: string) => {
// 检查是否已经添加过了
let s = state.TabsContentArr.filter(function (val: any, index: number) {
return activeMenu == val.url
});
// 如果没有添加过
if (s.length == 0) {
state.AsideMenu.forEach((v, i) => {
// 如果等于,表示一级菜单
if (activeMenu == v.web_href) {
state.TabsContentArr.push({
title: v.web_title,
url: v.web_href,
icon: v.icon,
closable: true
})
} else {
v.children.forEach((va, ix) => {
if (activeMenu == va.web_href) {
state.TabsContentArr.push({
title: va.web_title,
url: va.web_href,
icon: va.icon,
closable: true
})
}
})
}
})
}
},
// 切换激活
SET_TABACTIVE: (state: state, active: string) => {
state.TabsActive = active
},
// 移除激活
SET_REMOVETABS: (state: state, targetName: string) => {
let tabs = state.TabsContentArr;
let activeName = state.TabsActive;
// 如果删除的是当前激活菜单
if (activeName === targetName) {
tabs.forEach((tab: { [key: string]: any }, index: number) => {
if (tab.url === targetName) {
let nextTab: { [key: string]: any } = tabs[index + 1] || tabs[index - 1];
if (nextTab) {
activeName = nextTab.url;
}
}
});
}
state.TabsActive = activeName;
state.TabsContentArr = tabs.filter((tab: { [key: string]: any }) => {
return tab.url !== targetName
});
},
// 修改状态
SET_LOGINSTATUS: (state: state, status: boolean) => {
state.isLogin = status
}
},
}

1
src/core/types/.pydio Normal file
View File

@@ -0,0 +1 @@
e5b979e5-1ac3-429c-bf03-7d570eba9033

View File

@@ -0,0 +1,11 @@
/*
* Copyright (c) 2020. bmy
*/
import Component from 'vue-class-component'
Component.registerHooks([
'beforeRouteEnter',
'beforeRouteLeave',
'beforeRouteUpdate'
])

359
src/core/types/process.d.ts vendored Normal file
View File

@@ -0,0 +1,359 @@
// Type definitions for webpack (module API) 1.15
// Project: https://github.com/webpack/webpack
// Definitions by: use-strict <https://github.com/use-strict>
// rhonsby <https://github.com/rhonsby>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.1
/**
* Webpack module API - variables and global functions available inside modules
*/
declare namespace __WebpackModuleApi {
interface RequireResolve {
(id: string): string | number;
}
interface RequireContext {
keys(): string[];
(id: string): any;
<T>(id: string): T;
resolve(id: string): string;
/** The module id of the context module. This may be useful for module.hot.accept. */
id: string;
}
interface RequireFunction {
/**
* Returns the exports from a dependency. The call is sync. No request to the server is fired. The compiler ensures that the dependency is available.
*/
(path: string): any;
<T>(path: string): T;
/**
* Behaves similar to require.ensure, but the callback is called with the exports of each dependency in the paths array. There is no option to provide a chunk name.
*/
(paths: string[], callback: (...modules: any[]) => void): void;
/**
* Download additional dependencies on demand. The paths array lists modules that should be available. When they are, callback is called. If the callback is a function expression, dependencies in that source part are extracted and also loaded on demand. A single request is fired to the server, except if all modules are already available.
*
* This creates a chunk. The chunk can be named. If a chunk with this name already exists, the dependencies are merged into that chunk and that chunk is used.
*/
ensure(paths: string[], callback: (require: NodeRequire) => void, chunkName?: string): void;
ensure(paths: string[], callback: (require: NodeRequire) => void, errorCallback?: (error: any) => void, chunkName?: string): void;
context(path: string, deep?: boolean, filter?: RegExp, mode?: "sync" | "eager" | "weak" | "lazy" | "lazy-once"): RequireContext;
/**
* Returns the module id of a dependency. The call is sync. No request to the server is fired. The compiler ensures that the dependency is available.
*
* The module id is a number in webpack (in contrast to node.js where it is a string, the filename).
*/
resolve: NodeJS.RequireResolve;
/**
* Like require.resolve, but doesn’t include the module into the bundle. It’s a weak dependency.
*/
resolveWeak(path: string): number | string;
/**
* Ensures that the dependency is available, but don’t execute it. This can be use for optimizing the position of a module in the chunks.
*/
include(path: string): void;
/**
* Multiple requires to the same module result in only one module execution and only one export. Therefore a cache in the runtime exists. Removing values from this cache cause new module execution and a new export. This is only needed in rare cases (for compatibility!).
*/
cache: {
[id: string]: NodeModule | undefined;
}
}
interface Module {
exports: any;
id: string;
filename: string;
loaded: boolean;
parent: NodeModule | null | undefined;
children: NodeModule[];
hot?: Hot;
}
// @ts-ignore
type ModuleId = string|number;
interface HotNotifierInfo {
type:
| 'self-declined'
| 'declined'
| 'unaccepted'
| 'accepted'
| 'disposed'
| 'accept-errored'
| 'self-accept-errored'
| 'self-accept-error-handler-errored';
/**
* The module in question.
*/
moduleId: number;
/**
* For errors: the module id owning the accept handler.
*/
dependencyId?: number;
/**
* For declined/accepted/unaccepted: the chain from where the update was propagated.
*/
chain?: number[];
/**
* For declined: the module id of the declining parent
*/
parentId?: number;
/**
* For accepted: the modules that are outdated and will be disposed
*/
outdatedModules?: number[];
/**
* For accepted: The location of accept handlers that will handle the update
*/
outdatedDependencies?: {
[dependencyId: number]: number[];
};
/**
* For errors: the thrown error
*/
error?: Error;
/**
* For self-accept-error-handler-errored: the error thrown by the module
* before the error handler tried to handle it.
*/
originalError?: Error;
}
interface Hot {
/**
* Accept code updates for the specified dependencies. The callback is called when dependencies were replaced.
* @param dependencies
* @param callback
*/
accept(dependencies: string[], callback?: (updatedDependencies: ModuleId[]) => void): void;
/**
* Accept code updates for the specified dependencies. The callback is called when dependencies were replaced.
* @param dependency
* @param callback
*/
accept(dependency: string, callback?: () => void): void;
/**
* Accept code updates for this module without notification of parents.
* This should only be used if the module doesn’t export anything.
* The errHandler can be used to handle errors that occur while loading the updated module.
* @param errHandler
*/
accept(errHandler?: (err: Error) => void): void;
/**
* Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline".
*/
decline(dependencies: string[]): void;
/**
* Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline".
*/
decline(dependency: string): void;
/**
* Flag the current module as not update-able. If updated the update code would fail with code "decline".
*/
decline(): void;
/**
* Add a one time handler, which is executed when the current module code is replaced.
* Here you should destroy/remove any persistent resource you have claimed/created.
* If you want to transfer state to the new module, add it to data object.
* The data will be available at module.hot.data on the new module.
* @param callback
*/
dispose(callback: (data: any) => void): void;
dispose(callback: <T>(data: T) => void): void;
/**
* Add a one time handler, which is executed when the current module code is replaced.
* Here you should destroy/remove any persistent resource you have claimed/created.
* If you want to transfer state to the new module, add it to data object.
* The data will be available at module.hot.data on the new module.
* @param callback
*/
addDisposeHandler(callback: (data: any) => void): void;
addDisposeHandler<T>(callback: (data: T) => void): void;
/**
* Remove a handler.
* This can useful to add a temporary dispose handler. You could i. e. replace code while in the middle of a multi-step async function.
* @param callback
*/
removeDisposeHandler(callback: (data: any) => void): void;
removeDisposeHandler<T>(callback: (data: T) => void): void;
/**
* Throws an exceptions if status() is not idle.
* Check all currently loaded modules for updates and apply updates if found.
* If no update was found, the callback is called with null.
* If autoApply is truthy the callback will be called with all modules that were disposed.
* apply() is automatically called with autoApply as options parameter.
* If autoApply is not set the callback will be called with all modules that will be disposed on apply().
* @param autoApply
* @param callback
*/
check(autoApply: boolean, callback: (err: Error, outdatedModules: ModuleId[]) => void): void;
/**
* Throws an exceptions if status() is not idle.
* Check all currently loaded modules for updates and apply updates if found.
* If no update was found, the callback is called with null.
* The callback will be called with all modules that will be disposed on apply().
* @param callback
*/
check(callback: (err: Error, outdatedModules: ModuleId[]) => void): void;
/**
* If status() != "ready" it throws an error.
* Continue the update process.
* @param options
* @param callback
*/
apply(options: AcceptOptions, callback: (err: Error, outdatedModules: ModuleId[]) => void): void;
/**
* If status() != "ready" it throws an error.
* Continue the update process.
* @param callback
*/
apply(callback: (err: Error, outdatedModules: ModuleId[]) => void): void;
/**
* Return one of idle, check, watch, watch-delay, prepare, ready, dispose, apply, abort or fail.
*/
status(): string;
/** Register a callback on status change. */
status(callback: (status: string) => void): void;
/** Register a callback on status change. */
addStatusHandler(callback: (status: string) => void): void;
/**
* Remove a registered status change handler.
* @param callback
*/
removeStatusHandler(callback: (status: string) => void): void;
active: boolean;
data: any;
}
interface AcceptOptions {
/**
* If true the update process continues even if some modules are not accepted (and would bubble to the entry point).
*/
ignoreUnaccepted?: boolean;
/**
* Ignore changes made to declined modules.
*/
ignoreDeclined?: boolean;
/**
* Ignore errors throw in accept handlers, error handlers and while reevaluating module.
*/
ignoreErrored?: boolean;
/**
* Notifier for declined modules.
*/
onDeclined?: (info: HotNotifierInfo) => void;
/**
* Notifier for unaccepted modules.
*/
onUnaccepted?: (info: HotNotifierInfo) => void;
/**
* Notifier for accepted modules.
*/
onAccepted?: (info: HotNotifierInfo) => void;
/**
* Notifier for disposed modules.
*/
onDisposed?: (info: HotNotifierInfo) => void;
/**
* Notifier for errors.
*/
onErrored?: (info: HotNotifierInfo) => void;
/**
* Indicates that apply() is automatically called by check function
*/
autoApply?: boolean;
}
/**
* Inside env you can pass any variable
*/
interface NodeProcess {
// @ts-ignore
env: {
NODE_ENV: string
};
}
// @ts-ignore
type __Require1 = (id: string) => any;
// @ts-ignore
type __Require2 = <T>(id: string) => T;
// @ts-ignore
type RequireLambda = __Require1 & __Require2;
}
interface NodeRequire extends NodeJS.Require {}
declare var require: NodeRequire;
/**
* The resource query of the current module.
*
* e.g. __resourceQuery === "?test" // Inside "file.js?test"
*/
declare var __resourceQuery: string;
/**
* Equals the config options output.publicPath.
*/
declare var __webpack_public_path__: string;
/**
* The raw require function. This expression isn’t parsed by the Parser for dependencies.
*/
declare var __webpack_require__: any;
/**
* The internal chunk loading function
*
* @param chunkId The id for the chunk to load.
* @param callback A callback function called once the chunk is loaded.
*/
declare var __webpack_chunk_load__: (chunkId: any, callback: (require: __WebpackModuleApi.RequireLambda) => void) => void;
/**
* Access to the internal object of all modules.
*/
declare var __webpack_modules__: any[];
/**
* Access to the hash of the compilation.
*
* Only available with the HotModuleReplacementPlugin or the ExtendedAPIPlugin
*/
declare var __webpack_hash__: any;
/**
* Generates a require function that is not parsed by webpack. Can be used to do cool stuff with a global require function if available.
*/
declare var __non_webpack_require__: any;
/**
* Adds nonce to all scripts that webpack loads.
*
* To activate the feature a __webpack_nonce__ variable needs to be set in your entry script.
*/
declare var __webpack_nonce__: string;
/**
* Equals the config option debug
*/
declare var DEBUG: boolean;
interface NodeModule extends NodeJS.Module {}
declare var module: NodeModule;
/**
* Declare process variable
*/
declare namespace NodeJS {
interface Process extends __WebpackModuleApi.NodeProcess {}
interface RequireResolve extends __WebpackModuleApi.RequireResolve {}
interface Module extends __WebpackModuleApi.Module {}
interface Require extends __WebpackModuleApi.RequireFunction {}
}
declare var process: NodeJS.Process;

48
src/core/types/shims-tsx.d.ts vendored Normal file
View File

@@ -0,0 +1,48 @@
import Vue, { VNode } from 'vue'
declare global {
namespace Vue {
any
}
}
declare global {
namespace JSX {
interface ElementAttributesProperty {
$props: any // 设置类组件的props类型检查属性
}
// tslint:disable no-empty-interface
interface Element extends VNode {
}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {
}
interface IntrinsicAttributes {
// 给组件元素增加属性
on?: any
vModel?: any
vShow?: boolean
value?: any
oninput?: Function
nativeOnClick?: (event: MouseEvent) => void
oncontextmenu?: (event: MouseEvent) => void
onmouseup?: (event: MouseEvent) => void
onclick?: (event: MouseEvent) => void
onclick_prevent?: (event: MouseEvent) => void
ref?: string
key?: string | number
class?: string | string[]
slot?: string
style?: Partial<CSSStyleDeclaration> | string | object | object[]
}
interface IntrinsicElements {
[elem: string]: any
}
}
}

8
src/core/types/shims-vue.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
/*
* Copyright (c) 2020. bmy
*/
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}

1
src/core/utils/.pydio Normal file
View File

@@ -0,0 +1 @@
23f23313-fd2c-4dfc-aeaa-6758f2f76ec2

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2020. bmy
*/
import { ConfigureConfig } from "@config/configure.config";
import { GlobalMethod } from "@ann/register.annotation";
export class IndexUtils {
/**
* 动态返回接口基地址
* @constructor
*/
public static CheckAjaxUrl(): string {
if(process.env.NODE_ENV === 'production') {
return ConfigureConfig.AjaxConfig.ProdUrl;
} else {
return ConfigureConfig.AjaxConfig.DevUrl;
}
}
/**
* 方法上打上 @GlobalMethod() 注解,这个方法会自动成为vue的全局方法
* 组件中直接:this.$setToken() 即可
*/
@GlobalMethod
public setToken(args: string): void {
localStorage.setItem("token", args)
}
@GlobalMethod
public setStorage<T extends [] | {} | string>(key: string, data: T): void {
if (data.constructor == Array || data.constructor == Object) {
localStorage.setItem(`moehu_${key}`, JSON.stringify(data));
} else {
// @ts-ignore
localStorage.setItem(`moehu_${key}`, data.toString());
}
}
@GlobalMethod
public getStorage(key: String): typeof JSON | boolean | string{
let Storage: string | null = localStorage.getItem(`moehu_${key}`);
if (Storage == null) {
return false
} else {
try {
return JSON.parse(Storage);
} catch (e) {
return Storage;
}
}
}
@GlobalMethod
public isPhone(phone: string): boolean {
return /^1[3-9]\d{9}$/.test(phone)
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2023. bmy
* Email:2271608011@qq.com
* Github:https://github.com/helpcode
*/
import VueRouter from 'vue-router';
export default class NavigationGuardsUtils {
public beforeEach(Router: VueRouter) : void {
Router.beforeEach((to, from, next) => {
document.title = to.meta && to.meta.title;
if (to.meta && to.meta.isLogin) {
if (localStorage.getItem("moehu_token") != null) {
next()
} else {
next({
path: '/login'
})
}
} else {
if (localStorage.getItem("moehu_token") != null
&& to.path == "/login") {
Router.back();
}
next()
}
});
}
public afterEach(Router: VueRouter) : void {
Router.afterEach((to, from) => {
console.log("Router.afterEach")
})
}
}