feat: 优化常量助手函数
parent
56efcc0919
commit
7f88e736e2
4
.env
4
.env
|
|
@ -6,9 +6,9 @@ VITE_TITLE = 绝弹管理后台
|
||||||
# 网站副标题
|
# 网站副标题
|
||||||
VITE_SUBTITLE = 快速开发web应用的模板工具
|
VITE_SUBTITLE = 快速开发web应用的模板工具
|
||||||
# API接口前缀:参见 axios 的 baseURL
|
# API接口前缀:参见 axios 的 baseURL
|
||||||
VITE_API_PREFIX = http://127.0.0.1:3030/
|
VITE_API = http://127.0.0.1:3030/
|
||||||
# API文档地址:需返回符合 OPENAPI 规范的json内容
|
# API文档地址:需返回符合 OPENAPI 规范的json内容
|
||||||
VITE_API_SWAGGER = http://127.0.0.1:3030/openapi.json
|
VITE_OPENAPI = http://127.0.0.1:3030/openapi.json
|
||||||
|
|
||||||
# =====================================================================================
|
# =====================================================================================
|
||||||
# 开发设置
|
# 开发设置
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,19 @@
|
||||||
# 工作流名称,可自定义
|
|
||||||
name: 自动部署
|
|
||||||
# 事件监听,决定什么时候触发该工作流内的任务
|
|
||||||
on:
|
on:
|
||||||
# 在master分支推动到github时触发
|
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [master]
|
||||||
# 任务集合,可包含多个任务
|
|
||||||
jobs:
|
jobs:
|
||||||
# 任务名称
|
|
||||||
build:
|
build:
|
||||||
# 运行的操作系统
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
# 步骤集合,可包含多个步骤
|
|
||||||
steps:
|
steps:
|
||||||
# 单个步骤,没有名称,直接使用一个action
|
- name: checkout
|
||||||
- uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
# 单个步骤,带有名称,带有参数
|
- name: build
|
||||||
- name: build and deploy
|
|
||||||
run: |
|
run: |
|
||||||
npm install
|
corepack enable
|
||||||
npm run build
|
pnpm install
|
||||||
cd dist
|
pnpm build
|
||||||
git config --global user.name "juetan"
|
- name: deploy
|
||||||
git config --global user.email "810335188@qq.com"
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
git init
|
with:
|
||||||
git add -A
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
git commit -m "Build through github action"
|
publish_dir: ./dist
|
||||||
git push -f "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" master:gh-pages
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const env = loadEnv("development", process.cwd());
|
||||||
|
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
const output = await generateApi({
|
const output = await generateApi({
|
||||||
url: env.VITE_API_SWAGGER,
|
url: env.VITE_API_OPENAPI,
|
||||||
templates: path.resolve(__dirname, "./template"),
|
templates: path.resolve(__dirname, "./template"),
|
||||||
output: path.resolve(process.cwd(), "src/api/service"),
|
output: path.resolve(process.cwd(), "src/api/service"),
|
||||||
name: "Api.ts",
|
name: "Api.ts",
|
||||||
|
|
@ -28,44 +28,14 @@ const run = async () => {
|
||||||
parser: "typescript",
|
parser: "typescript",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// const { configuration, getTemplate, renderTemplate, createFile } = output
|
|
||||||
// const { config } = configuration
|
|
||||||
// const { templateInfos } = config
|
|
||||||
// const templateMap = templateInfos.reduce((acc, { fileName, name }) => ({
|
|
||||||
// ...acc,
|
|
||||||
// [name]: getTemplate({ fileName, name }),
|
|
||||||
// }),
|
|
||||||
// {});
|
|
||||||
// const files = [
|
|
||||||
// {
|
|
||||||
// path: config.output,
|
|
||||||
// fileName: 'dataContracts.ts',
|
|
||||||
// content: renderTemplate(templateMap.dataContracts, configuration),
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: config.output,
|
|
||||||
// fileName: 'httpClient.ts',
|
|
||||||
// content: renderTemplate(templateMap.httpClient, configuration),
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: config.output,
|
|
||||||
// fileName: 'apiClient.ts',
|
|
||||||
// content: renderTemplate(templateMap.api, configuration),
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// for (const file of files) {
|
|
||||||
// createFile(file)
|
|
||||||
// } pathParams, queryParams, bodyParams, headerParams, formDataParams, responses, method, url
|
|
||||||
debugger
|
|
||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模板修改备注:
|
* 模板修改备注:
|
||||||
*
|
*
|
||||||
* route-docs.ejs
|
* route-docs.ejs
|
||||||
* - 移除 `@description` 关键字
|
* - 移除 `@description` 关键字
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ class Service extends Api<unknown> {
|
||||||
* API 接口实例
|
* API 接口实例
|
||||||
* @see src/api/instance/instance.ts
|
* @see src/api/instance/instance.ts
|
||||||
*/
|
*/
|
||||||
export const api = new Service({
|
const api = new Service({
|
||||||
baseURL: import.meta.env.VITE_API_PREFIX,
|
baseURL: import.meta.env.VITE_API,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -64,10 +64,9 @@ api.instance.interceptors.response.use(
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
const userStore = useUserStore(store);
|
|
||||||
error.config.closeToast?.();
|
error.config.closeToast?.();
|
||||||
|
const userStore = useUserStore(store);
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
console.log("response error", error.response);
|
|
||||||
const code = error.response.data?.code;
|
const code = error.response.data?.code;
|
||||||
if (code === 4050 || code === 4051) {
|
if (code === 4050 || code === 4051) {
|
||||||
userStore.clearUser();
|
userStore.clearUser();
|
||||||
|
|
@ -75,8 +74,10 @@ api.instance.interceptors.response.use(
|
||||||
}
|
}
|
||||||
} else if (error.request) {
|
} else if (error.request) {
|
||||||
console.log("request error", error.request);
|
console.log("request error", error.request);
|
||||||
Message.error(`提示:请求失败,检查网络状态或稍后再试!`);
|
Message.error(`提示:网络异常,请检查网络是否正常或稍后重试!`);
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export { api };
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { modal } from "@/utils/modal";
|
import { delConfirm } from "@/utils";
|
||||||
import { Doption, Dropdown, Link, Message, TableColumnData } from "@arco-design/web-vue";
|
import { Doption, Dropdown, Link, Message, TableColumnData } from "@arco-design/web-vue";
|
||||||
import { isArray, merge } from "lodash-es";
|
import { isArray, merge } from "lodash-es";
|
||||||
import { reactive } from "vue";
|
import { reactive } from "vue";
|
||||||
|
|
@ -14,7 +14,7 @@ const onClick = async (item: any, columnData: any, getTable: any) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (item.type === "delete") {
|
if (item.type === "delete") {
|
||||||
await modal.delConfirm();
|
await delConfirm();
|
||||||
try {
|
try {
|
||||||
const resData: any = await item?.onClick?.(columnData);
|
const resData: any = await item?.onClick?.(columnData);
|
||||||
const message = resData?.data?.message;
|
const message = resData?.data?.message;
|
||||||
|
|
@ -191,7 +191,7 @@ export const useTable = (optionsOrFn: UseTableOptions | (() => UseTableOptions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const merged = merge({ modalProps: { titleAlign: 'start', closable: false } }, options.create, options.modify);
|
const merged = merge({ modalProps: { titleAlign: "start", closable: false } }, options.create, options.modify);
|
||||||
options.modify = useFormModal(merged as any) as any;
|
options.modify = useFormModal(merged as any) as any;
|
||||||
} else {
|
} else {
|
||||||
options.modify = useFormModal(options.modify as any) as any;
|
options.modify = useFormModal(options.modify as any) as any;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { extendEnum } from "@/utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别枚举
|
||||||
|
*/
|
||||||
|
enum GenderEnum {
|
||||||
|
/**
|
||||||
|
* 男
|
||||||
|
*/
|
||||||
|
Man = 1,
|
||||||
|
/**
|
||||||
|
* 女
|
||||||
|
*/
|
||||||
|
Famale = 2,
|
||||||
|
/**
|
||||||
|
* 保密
|
||||||
|
*/
|
||||||
|
Secret = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别
|
||||||
|
*/
|
||||||
|
const GenderDict = extendEnum(GenderEnum, [
|
||||||
|
{
|
||||||
|
value: GenderEnum.Man,
|
||||||
|
label: "男",
|
||||||
|
color: "blue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: GenderEnum.Famale,
|
||||||
|
label: "女",
|
||||||
|
color: "pink",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: GenderEnum.Secret,
|
||||||
|
label: "保密",
|
||||||
|
color: "gray",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
export { GenderEnum, GenderDict };
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./gender";
|
||||||
|
|
@ -39,9 +39,9 @@
|
||||||
<a-space :size="16" direction="vertical">
|
<a-space :size="16" direction="vertical">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<a-checkbox checked="rememberPassword">记住我</a-checkbox>
|
<a-checkbox checked="rememberPassword">记住我</a-checkbox>
|
||||||
<a-link @click="onForgetPasswordClick">忘记密码?</a-link>
|
<a-link @click="onForgetPassword">忘记密码?</a-link>
|
||||||
</div>
|
</div>
|
||||||
<a-button type="primary" html-type="submit" long class="mt-2" :loading="loading" @click="onSubmitClick">
|
<a-button type="primary" html-type="submit" long class="mt-2" :loading="loading" @click="onSubmitForm">
|
||||||
立即登录
|
立即登录
|
||||||
</a-button>
|
</a-button>
|
||||||
<p type="text" long class="text-gray-400 text-center m-0">暂不支持其他方式登录</p>
|
<p type="text" long class="text-gray-400 text-center m-0">暂不支持其他方式登录</p>
|
||||||
|
|
@ -85,7 +85,7 @@ const formRules: Record<string, FieldRule[]> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const onForgetPasswordClick = () => {
|
const onForgetPassword = () => {
|
||||||
Modal.info({
|
Modal.info({
|
||||||
title: "忘记密码?",
|
title: "忘记密码?",
|
||||||
content: "如已忘记密码,请联系管理员进行密码重置!",
|
content: "如已忘记密码,请联系管理员进行密码重置!",
|
||||||
|
|
@ -94,9 +94,8 @@ const onForgetPasswordClick = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmitClick = async () => {
|
const onSubmitForm = async () => {
|
||||||
const errors = await formRef.value?.validate();
|
if (await formRef.value?.validate()) {
|
||||||
if (errors) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
@ -107,9 +106,7 @@ const onSubmitClick = async () => {
|
||||||
router.push({ path: (route.query.redirect as string) || "/" });
|
router.push({ path: (route.query.redirect as string) || "/" });
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const message = error?.response?.data?.message;
|
const message = error?.response?.data?.message;
|
||||||
if (message) {
|
message && Message.warning(`提示:${message}`);
|
||||||
Message.warning(`提示:${message}`);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,14 +87,6 @@ const table = useTable({
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
title: "新建用户",
|
title: "新建用户",
|
||||||
trigger: () => (
|
|
||||||
<Button type="primary">
|
|
||||||
{{
|
|
||||||
icon: () => <i class="icon-park-outline-people-plus-one" />,
|
|
||||||
default: () => "添加",
|
|
||||||
}}
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
modalProps: {
|
modalProps: {
|
||||||
width: 772,
|
width: 772,
|
||||||
maskClosable: false,
|
maskClosable: false,
|
||||||
|
|
@ -120,8 +112,8 @@ const table = useTable({
|
||||||
label: "个人描述",
|
label: "个人描述",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
itemProps: {
|
itemProps: {
|
||||||
class: 'col-span-2'
|
class: "col-span-2",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "password",
|
field: "password",
|
||||||
|
|
|
||||||
|
|
@ -7,22 +7,15 @@ export {}
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
AAlert: typeof import('@arco-design/web-vue')['Alert']
|
|
||||||
AAvatar: typeof import('@arco-design/web-vue')['Avatar']
|
AAvatar: typeof import('@arco-design/web-vue')['Avatar']
|
||||||
ABreadcrumb: typeof import('@arco-design/web-vue')['Breadcrumb']
|
|
||||||
ABreadcrumbItem: typeof import('@arco-design/web-vue')['BreadcrumbItem']
|
|
||||||
AButton: typeof import('@arco-design/web-vue')['Button']
|
AButton: typeof import('@arco-design/web-vue')['Button']
|
||||||
ACard: typeof import('@arco-design/web-vue')['Card']
|
|
||||||
ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
|
ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
|
||||||
ACheckboxGroup: typeof import('@arco-design/web-vue')['CheckboxGroup']
|
|
||||||
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider']
|
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider']
|
||||||
ADatePicker: typeof import('@arco-design/web-vue')['DatePicker']
|
|
||||||
ADoption: typeof import('@arco-design/web-vue')['Doption']
|
ADoption: typeof import('@arco-design/web-vue')['Doption']
|
||||||
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
|
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
|
||||||
ADropdown: typeof import('@arco-design/web-vue')['Dropdown']
|
ADropdown: typeof import('@arco-design/web-vue')['Dropdown']
|
||||||
AForm: typeof import('@arco-design/web-vue')['Form']
|
AForm: typeof import('@arco-design/web-vue')['Form']
|
||||||
AFormItem: typeof import('@arco-design/web-vue')['FormItem']
|
AFormItem: typeof import('@arco-design/web-vue')['FormItem']
|
||||||
AImage: typeof import('@arco-design/web-vue')['Image']
|
|
||||||
AInput: typeof import('@arco-design/web-vue')['Input']
|
AInput: typeof import('@arco-design/web-vue')['Input']
|
||||||
AInputPassword: typeof import('@arco-design/web-vue')['InputPassword']
|
AInputPassword: typeof import('@arco-design/web-vue')['InputPassword']
|
||||||
ALayout: typeof import('@arco-design/web-vue')['Layout']
|
ALayout: typeof import('@arco-design/web-vue')['Layout']
|
||||||
|
|
@ -30,25 +23,12 @@ declare module '@vue/runtime-core' {
|
||||||
ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader']
|
ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader']
|
||||||
ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider']
|
ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider']
|
||||||
ALink: typeof import('@arco-design/web-vue')['Link']
|
ALink: typeof import('@arco-design/web-vue')['Link']
|
||||||
AList: typeof import('@arco-design/web-vue')['List']
|
|
||||||
AListItem: typeof import('@arco-design/web-vue')['ListItem']
|
|
||||||
AListItemMeta: typeof import('@arco-design/web-vue')['ListItemMeta']
|
|
||||||
AMenu: typeof import('@arco-design/web-vue')['Menu']
|
AMenu: typeof import('@arco-design/web-vue')['Menu']
|
||||||
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
|
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
|
||||||
AMenuItemGroup: typeof import('@arco-design/web-vue')['MenuItemGroup']
|
AMenuItemGroup: typeof import('@arco-design/web-vue')['MenuItemGroup']
|
||||||
AModal: typeof import('@arco-design/web-vue')['Modal']
|
|
||||||
APagination: typeof import('@arco-design/web-vue')['Pagination']
|
|
||||||
ARadio: typeof import('@arco-design/web-vue')['Radio']
|
|
||||||
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
|
|
||||||
ASpace: typeof import('@arco-design/web-vue')['Space']
|
ASpace: typeof import('@arco-design/web-vue')['Space']
|
||||||
ASwitch: typeof import('@arco-design/web-vue')['Switch']
|
|
||||||
ATabPane: typeof import('@arco-design/web-vue')['TabPane']
|
|
||||||
ATabs: typeof import('@arco-design/web-vue')['Tabs']
|
|
||||||
ATag: typeof import('@arco-design/web-vue')['Tag']
|
ATag: typeof import('@arco-design/web-vue')['Tag']
|
||||||
ATextarea: typeof import('@arco-design/web-vue')['Textarea']
|
|
||||||
ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
|
ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
|
||||||
ATree: typeof import('@arco-design/web-vue')['Tree']
|
|
||||||
AUpload: typeof import('@arco-design/web-vue')['Upload']
|
|
||||||
BreadCrumb: typeof import('./../components/breadcrumb/bread-crumb.vue')['default']
|
BreadCrumb: typeof import('./../components/breadcrumb/bread-crumb.vue')['default']
|
||||||
BreadPage: typeof import('./../components/breadcrumb/bread-page.vue')['default']
|
BreadPage: typeof import('./../components/breadcrumb/bread-page.vue')['default']
|
||||||
Page403: typeof import('./../components/error/page-403.vue')['default']
|
Page403: typeof import('./../components/error/page-403.vue')['default']
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ interface ImportMetaEnv {
|
||||||
/**
|
/**
|
||||||
* API 地址
|
* API 地址
|
||||||
*/
|
*/
|
||||||
VITE_API_BASE_URL: string;
|
VITE_API: string;
|
||||||
/**
|
/**
|
||||||
* 开发服务器主机
|
* 开发服务器主机
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
|
|
||||||
type MergeIntersection<A> = A extends infer T ? { [Key in keyof T]: T[Key] } : never;
|
|
||||||
|
|
||||||
interface Item {
|
|
||||||
label: string;
|
|
||||||
value: any;
|
|
||||||
enumKey: string;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConstantType<T extends readonly Item[]> = MergeIntersection<
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 枚举值
|
|
||||||
*/
|
|
||||||
[K in T[number]as K["enumKey"]]: K["value"];
|
|
||||||
} & {
|
|
||||||
/**
|
|
||||||
* 格式化
|
|
||||||
* @param value value值
|
|
||||||
* @param key 指定返回的属性,默认为label
|
|
||||||
*/
|
|
||||||
format<K extends T[number]["value"]>(value: K, key?: keyof T[number]): any;
|
|
||||||
/**
|
|
||||||
* 所有值组成的数组
|
|
||||||
*/
|
|
||||||
values: any[];
|
|
||||||
/**
|
|
||||||
* 返回数组,由指定属性的值组成
|
|
||||||
*/
|
|
||||||
prop<K extends keyof T[number]>(key: K): T[number][K][];
|
|
||||||
/**
|
|
||||||
* 获取指定值的项
|
|
||||||
*/
|
|
||||||
pick(...values: T[number]["value"][]): Item[];
|
|
||||||
/**
|
|
||||||
* 排除指定值的项
|
|
||||||
*/
|
|
||||||
omit(...values: T[number]["value"][]): Item[];
|
|
||||||
/**
|
|
||||||
* 原始项数组
|
|
||||||
*/
|
|
||||||
raw: T;
|
|
||||||
/**
|
|
||||||
* 字典项映射
|
|
||||||
*/
|
|
||||||
map: {
|
|
||||||
[k in T[number]as k["value"]]: k;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供公共方法
|
|
||||||
*/
|
|
||||||
class Constanter {
|
|
||||||
raw: Item[] = [];
|
|
||||||
pick(...values: any[]) {
|
|
||||||
return this.raw.filter((item) => values.includes(item.value));
|
|
||||||
}
|
|
||||||
omit(...values: any[]) {
|
|
||||||
return this.raw.filter((item) => !values.includes(item.value));
|
|
||||||
}
|
|
||||||
each(key: string) {
|
|
||||||
return this.raw.map((item) => item[key]);
|
|
||||||
}
|
|
||||||
format(value: any, key: string = "label") {
|
|
||||||
return this.raw.find((item) => item.value === value)?.[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 定义字典常量
|
|
||||||
*/
|
|
||||||
export function defineConstants<T extends readonly Item[]>(items: T): ConstantType<T> {
|
|
||||||
const constants: any = {
|
|
||||||
items,
|
|
||||||
map: {},
|
|
||||||
values: [],
|
|
||||||
};
|
|
||||||
for (const item of items) {
|
|
||||||
constants[item.enumKey] = item.value;
|
|
||||||
constants.map[item.value] = item;
|
|
||||||
constants.values.push(item.value);
|
|
||||||
}
|
|
||||||
return Object.setPrototypeOf(constants, Constanter.prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
// const media = defineConstants([
|
|
||||||
// {
|
|
||||||
// label: "视频",
|
|
||||||
// value: 1,
|
|
||||||
// enumKey: "VIDEO",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// label: "图片",
|
|
||||||
// value: 2,
|
|
||||||
// enumKey: "IMAGE",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// label: "文本",
|
|
||||||
// value: 3,
|
|
||||||
// enumKey: "TEXT",
|
|
||||||
// },
|
|
||||||
// ] as const);
|
|
||||||
|
|
||||||
// console.log("media", media, media.VIDEO, media.IMAGE, media.TEXT);
|
|
||||||
// console.log("media pick", media.pick(media.VIDEO));
|
|
||||||
// console.log("media omit", media.omit(media.TEXT));
|
|
||||||
// console.log("media each", media.prop("label"));
|
|
||||||
// console.log("media format", media.format(2));
|
|
||||||
// console.log("media maps", media.map);
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Modal, ModalConfig } from "@arco-design/web-vue";
|
||||||
|
import { merge } from "lodash-es";
|
||||||
|
|
||||||
|
type DelOptions = string | Partial<Omit<ModalConfig, "onOk" | "onCancel">>;
|
||||||
|
|
||||||
|
const delOptions = {
|
||||||
|
title: "提示",
|
||||||
|
titleAlign: "start",
|
||||||
|
width: 432,
|
||||||
|
content: "确定删除该数据吗?注意:该操作不可恢复!",
|
||||||
|
maskClosable: false,
|
||||||
|
closable: false,
|
||||||
|
okText: "确定",
|
||||||
|
okButtonProps: {
|
||||||
|
status: "danger",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const delConfirm = (config: DelOptions = {}) => {
|
||||||
|
if (typeof config === "string") {
|
||||||
|
config = { content: config };
|
||||||
|
}
|
||||||
|
const merged = merge(delOptions, config);
|
||||||
|
return new Promise<void>((onOk: () => void, onCancel) => {
|
||||||
|
Modal.open({ ...merged, onOk, onCancel });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { delConfirm };
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
type MergeIntersection<A> = A extends infer T ? { [Key in keyof T]: T[Key] } : never;
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
label: string;
|
||||||
|
value: any;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProtoInterface<T extends readonly Item[]> {
|
||||||
|
/**
|
||||||
|
* 格式化
|
||||||
|
* @param value 值
|
||||||
|
* @param key 属性名,默认为 `label`
|
||||||
|
*/
|
||||||
|
fmt<K extends T[number]["value"]>(value: K, key?: keyof T[number]): any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回数组,由指定属性的值组成
|
||||||
|
* @description 默认返回 value 属性值组成的数组
|
||||||
|
*/
|
||||||
|
val<K extends keyof T[number]>(key: K): T[number][K][];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始项数组
|
||||||
|
*/
|
||||||
|
raw(): T;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典项映射
|
||||||
|
*/
|
||||||
|
map(): {
|
||||||
|
[k in T[number] as k["value"]]: k;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class Proto implements ProtoInterface<Item[]> {
|
||||||
|
_raw: Item[] = [];
|
||||||
|
|
||||||
|
fmt(value: any, key = "label") {
|
||||||
|
return this._raw.find((item) => item.value === value)?.[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
val(key: any = "value") {
|
||||||
|
return this._raw.map((item) => item[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
raw() {
|
||||||
|
return this._raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
map() {
|
||||||
|
return this._raw.reduce((acc, cur) => {
|
||||||
|
acc[cur.value] = cur;
|
||||||
|
return acc;
|
||||||
|
}, {} as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EnumType<T extends Object, R extends readonly Item[]> = MergeIntersection<T & ProtoInterface<R>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扩展枚举对象,添加额外的方法
|
||||||
|
* @param target 枚举对象
|
||||||
|
* @param items 对象数组
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function extendEnum<T extends Object, I extends readonly Item[]>(target: T, items: I): EnumType<T, I> {
|
||||||
|
Object.assign(target, { _raw: items });
|
||||||
|
Object.setPrototypeOf(target, Proto.prototype);
|
||||||
|
return target as any;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./extendEnum";
|
||||||
|
export * from "./delConfirm";
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
import { Modal, ModalConfig } from "@arco-design/web-vue";
|
|
||||||
import { merge } from "lodash-es";
|
|
||||||
|
|
||||||
export const modal = {
|
|
||||||
delConfirm(config: Partial<Omit<ModalConfig, "onOk" | "onCancel">> = {}) {
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
const mergedConfig = merge(
|
|
||||||
{
|
|
||||||
title: "提示",
|
|
||||||
titleAlign: "start",
|
|
||||||
width: 432,
|
|
||||||
content: "确定删除该数据吗?注意:该操作不可恢复!",
|
|
||||||
maskClosable: false,
|
|
||||||
closable: false,
|
|
||||||
okText: "确定删除",
|
|
||||||
okButtonProps: {
|
|
||||||
status: "danger",
|
|
||||||
},
|
|
||||||
onOk: () => {
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
onCancel: () => {
|
|
||||||
reject();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
Modal.open(mergedConfig);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Loading…
Reference in New Issue