mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-08-28 09:33:52 +08:00
发布v2.2.10版本,更新内容请查看:https://github.com/bufanyun/hotgo/tree/v2.0/docs/guide-zh-CN/addon-version-upgrade.md
This commit is contained in:
@@ -1 +1 @@
|
||||
## HotGo 管理后台前端
|
||||
## HotGo 管理web前端
|
||||
|
24258
web/package-lock.json
generated
24258
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hotgo",
|
||||
"version": "2.1.3",
|
||||
"version": "2.2.10",
|
||||
"author": {
|
||||
"name": "MengShuai",
|
||||
"email": "133814250@qq.com",
|
||||
@@ -45,6 +45,7 @@
|
||||
"naive-ui": "^2.34.3",
|
||||
"node-sass": "^7.0.3",
|
||||
"pinia": "^2.0.14",
|
||||
"qrcode.vue": "3.3.3",
|
||||
"qs": "^6.10.3",
|
||||
"quill-image-uploader": "^1.2.4",
|
||||
"quill-magic-url": "^4.2.0",
|
||||
|
17
web/src/api/addons/hgexample/config/index.ts
Normal file
17
web/src/api/addons/hgexample/config/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { http } from '@/utils/http/axios';
|
||||
|
||||
export function getConfig(params) {
|
||||
return http.request({
|
||||
url: '/hgexample/config/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateConfig(params) {
|
||||
return http.request({
|
||||
url: '/hgexample/config/update',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
@@ -3,7 +3,7 @@ import { http, jumpExport } from '@/utils/http/axios';
|
||||
// 列表
|
||||
export function List(params) {
|
||||
return http.request({
|
||||
url: '/test/list',
|
||||
url: '/hgexample/table/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
@@ -12,7 +12,7 @@ export function List(params) {
|
||||
// 删除/批量删除
|
||||
export function Delete(params) {
|
||||
return http.request({
|
||||
url: '/test/delete',
|
||||
url: '/hgexample/table/delete',
|
||||
method: 'POST',
|
||||
params,
|
||||
});
|
||||
@@ -21,7 +21,7 @@ export function Delete(params) {
|
||||
// 添加/编辑
|
||||
export function Edit(params) {
|
||||
return http.request({
|
||||
url: '/test/edit',
|
||||
url: '/hgexample/table/edit',
|
||||
method: 'POST',
|
||||
params,
|
||||
});
|
||||
@@ -30,7 +30,7 @@ export function Edit(params) {
|
||||
// 修改状态
|
||||
export function Status(params) {
|
||||
return http.request({
|
||||
url: '/test/status',
|
||||
url: '/hgexample/table/status',
|
||||
method: 'POST',
|
||||
params,
|
||||
});
|
||||
@@ -39,7 +39,7 @@ export function Status(params) {
|
||||
// 操作开关
|
||||
export function Switch(params) {
|
||||
return http.request({
|
||||
url: '/test/switch',
|
||||
url: '/hgexample/table/switch',
|
||||
method: 'POST',
|
||||
params,
|
||||
});
|
||||
@@ -48,7 +48,7 @@ export function Switch(params) {
|
||||
// 详情
|
||||
export function View(params) {
|
||||
return http.request({
|
||||
url: '/test/view',
|
||||
url: '/hgexample/table/view',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
@@ -57,12 +57,12 @@ export function View(params) {
|
||||
// 获取最大排序
|
||||
export function MaxSort() {
|
||||
return http.request({
|
||||
url: '/test/maxSort',
|
||||
url: '/hgexample/table/maxSort',
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
// 导出
|
||||
export function Export(params) {
|
||||
jumpExport('/test/export', params);
|
||||
jumpExport('/hgexample/table/export', params);
|
||||
}
|
64
web/src/api/develop/addons.ts
Normal file
64
web/src/api/develop/addons.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { http } from '@/utils/http/axios';
|
||||
|
||||
export function List(params) {
|
||||
return http.request({
|
||||
url: '/addons/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function View(params) {
|
||||
return http.request({
|
||||
url: '/addons/view',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function Status(params) {
|
||||
return http.request({
|
||||
url: '/addons/status',
|
||||
method: 'POST',
|
||||
params,
|
||||
});
|
||||
}
|
||||
export function Selects(params) {
|
||||
return http.request({
|
||||
url: '/addons/selects',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function Build(params) {
|
||||
return http.request({
|
||||
url: '/addons/build',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function Install(params) {
|
||||
return http.request({
|
||||
url: '/addons/install',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function Upgrade(params) {
|
||||
return http.request({
|
||||
url: '/addons/upgrade',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function UnInstall(params) {
|
||||
return http.request({
|
||||
url: '/addons/uninstall',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
@@ -17,6 +17,7 @@ export function getConfig() {
|
||||
return http.request({
|
||||
url: ApiEnum.SiteConfig,
|
||||
method: 'get',
|
||||
headers: { hostname: location.hostname },
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-input-group>
|
||||
<n-input v-bind="$props" :value="formValue" :style="{ width: '70%' }" />
|
||||
<template v-if="option === 'ionicons5'">
|
||||
<Ionicons5Selector v-model:value="formValue" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<AntdSelector v-model:value="formValue" />
|
||||
</template>
|
||||
<n-input v-bind="$props" :value="formValue" :style="{ width: '70%' }" />
|
||||
</n-input-group>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -89,7 +89,7 @@
|
||||
import { ResultEnum } from '@/enums/httpEnum';
|
||||
import componentSetting from '@/settings/componentSetting';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { isArray, isJsonString, isNullOrUnDef } from '@/utils/is';
|
||||
import { isArray, isJsonString, isNullOrUnDef, isUrl } from '@/utils/is';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
||||
import { errorImg } from '@/utils/hotgo';
|
||||
const globSetting = useGlobSetting();
|
||||
@@ -217,7 +217,7 @@
|
||||
//组装完整图片地址
|
||||
function getImgUrl(url: string): string {
|
||||
const { imgUrl } = globSetting;
|
||||
return /(^http|https:\/\/)/g.test(url) ? url : `${imgUrl}${url}`;
|
||||
return isUrl(url) ? url : `${imgUrl}${url}`;
|
||||
}
|
||||
|
||||
function checkFileType(map: string[], fileType: string) {
|
||||
|
34
web/src/directives/copy.ts
Normal file
34
web/src/directives/copy.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* v-copy
|
||||
* 复制某个值至剪贴板
|
||||
* 接收参数:string类型/Ref<string>类型/Reactive<string>类型
|
||||
*/
|
||||
import type { Directive, DirectiveBinding } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
interface ElType extends HTMLElement {
|
||||
copyData: string | number;
|
||||
__handleClick__: any;
|
||||
}
|
||||
const copy: Directive = {
|
||||
mounted(el: ElType, binding: DirectiveBinding) {
|
||||
el.copyData = binding.value;
|
||||
el.addEventListener('click', handleClick);
|
||||
},
|
||||
updated(el: ElType, binding: DirectiveBinding) {
|
||||
el.copyData = binding.value;
|
||||
},
|
||||
beforeUnmount(el: ElType) {
|
||||
el.removeEventListener('click', el.__handleClick__);
|
||||
},
|
||||
};
|
||||
function handleClick(this: any) {
|
||||
const input = document.createElement('input');
|
||||
input.value = this.copyData.toLocaleString();
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
document.execCommand('Copy');
|
||||
document.body.removeChild(input);
|
||||
console.log('复制成功', this.copyData);
|
||||
}
|
||||
|
||||
export default copy;
|
31
web/src/directives/debounce.ts
Normal file
31
web/src/directives/debounce.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* v-debounce
|
||||
* 按钮防抖指令,可自行扩展至input
|
||||
* 接收参数:function类型
|
||||
*/
|
||||
import type { Directive, DirectiveBinding } from "vue";
|
||||
interface ElType extends HTMLElement {
|
||||
__handleClick__: () => any;
|
||||
}
|
||||
const debounce: Directive = {
|
||||
mounted(el: ElType, binding: DirectiveBinding) {
|
||||
if (typeof binding.value !== "function") {
|
||||
throw "callback must be a function";
|
||||
}
|
||||
let timer: NodeJS.Timeout | null = null;
|
||||
el.__handleClick__ = function () {
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
binding.value();
|
||||
}, 500);
|
||||
};
|
||||
el.addEventListener("click", el.__handleClick__);
|
||||
},
|
||||
beforeUnmount(el: ElType) {
|
||||
el.removeEventListener("click", el.__handleClick__);
|
||||
}
|
||||
};
|
||||
|
||||
export default debounce;
|
49
web/src/directives/draggable.ts
Normal file
49
web/src/directives/draggable.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
需求:实现一个拖拽指令,可在父元素区域任意拖拽元素。
|
||||
|
||||
思路:
|
||||
1、设置需要拖拽的元素为absolute,其父元素为relative。
|
||||
2、鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。
|
||||
3、鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值
|
||||
4、鼠标松开(onmouseup)时完成一次拖拽
|
||||
|
||||
使用:在 Dom 上加上 v-draggable 即可
|
||||
<div class="dialog-model" v-draggable></div>
|
||||
*/
|
||||
import type { Directive } from "vue";
|
||||
interface ElType extends HTMLElement {
|
||||
parentNode: any;
|
||||
}
|
||||
const draggable: Directive = {
|
||||
mounted: function (el: ElType) {
|
||||
el.style.cursor = "move";
|
||||
el.style.position = "absolute";
|
||||
el.onmousedown = function (e) {
|
||||
let disX = e.pageX - el.offsetLeft;
|
||||
let disY = e.pageY - el.offsetTop;
|
||||
document.onmousemove = function (e) {
|
||||
let x = e.pageX - disX;
|
||||
let y = e.pageY - disY;
|
||||
let maxX = el.parentNode.offsetWidth - el.offsetWidth;
|
||||
let maxY = el.parentNode.offsetHeight - el.offsetHeight;
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
} else if (x > maxX) {
|
||||
x = maxX;
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
} else if (y > maxY) {
|
||||
y = maxY;
|
||||
}
|
||||
el.style.left = x + "px";
|
||||
el.style.top = y + "px";
|
||||
};
|
||||
document.onmouseup = function () {
|
||||
document.onmousemove = document.onmouseup = null;
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
export default draggable;
|
41
web/src/directives/throttle.ts
Normal file
41
web/src/directives/throttle.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
需求:防止按钮在短时间内被多次点击,使用节流函数限制规定时间内只能点击一次。
|
||||
|
||||
思路:
|
||||
1、第一次点击,立即调用方法并禁用按钮,等延迟结束再次激活按钮
|
||||
2、将需要触发的方法绑定在指令上
|
||||
|
||||
使用:给 Dom 加上 v-throttle 及回调函数即可
|
||||
<button v-throttle="debounceClick">节流提交</button>
|
||||
*/
|
||||
import type { Directive, DirectiveBinding } from "vue";
|
||||
interface ElType extends HTMLElement {
|
||||
__handleClick__: () => any;
|
||||
disabled: boolean;
|
||||
}
|
||||
const throttle: Directive = {
|
||||
mounted(el: ElType, binding: DirectiveBinding) {
|
||||
if (typeof binding.value !== "function") {
|
||||
throw "callback must be a function";
|
||||
}
|
||||
let timer: NodeJS.Timeout | null = null;
|
||||
el.__handleClick__ = function () {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
if (!el.disabled) {
|
||||
el.disabled = true;
|
||||
binding.value();
|
||||
timer = setTimeout(() => {
|
||||
el.disabled = false;
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
el.addEventListener("click", el.__handleClick__);
|
||||
},
|
||||
beforeUnmount(el: ElType) {
|
||||
el.removeEventListener("click", el.__handleClick__);
|
||||
}
|
||||
};
|
||||
|
||||
export default throttle;
|
@@ -1,6 +1,10 @@
|
||||
import { App } from 'vue';
|
||||
|
||||
import { permission } from '@/directives/permission';
|
||||
import copy from '@/directives/copy';
|
||||
import debounce from '@/directives/debounce';
|
||||
import throttle from '@/directives/throttle';
|
||||
import draggable from '@/directives/draggable';
|
||||
|
||||
/**
|
||||
* 注册全局自定义指令
|
||||
@@ -9,4 +13,12 @@ import { permission } from '@/directives/permission';
|
||||
export function setupDirectives(app: App) {
|
||||
// 权限控制指令(演示)
|
||||
app.directive('permission', permission);
|
||||
// 复制指令
|
||||
app.directive('copy', copy);
|
||||
// 防抖指令
|
||||
app.directive('debounce', debounce);
|
||||
// 节流指令
|
||||
app.directive('throttle', throttle);
|
||||
// 拖拽指令
|
||||
app.directive('draggable', draggable);
|
||||
}
|
||||
|
@@ -45,6 +45,7 @@ export const routerGenerator = (routerMap, parent?): any[] => {
|
||||
// Recursion
|
||||
currentRouter.children = routerGenerator(item.children, currentRouter);
|
||||
}
|
||||
|
||||
return currentRouter;
|
||||
});
|
||||
};
|
||||
|
@@ -35,6 +35,12 @@ export interface UserInfoState {
|
||||
lastLoginIp: string;
|
||||
}
|
||||
|
||||
export interface ConfigState {
|
||||
domain: string;
|
||||
version: string;
|
||||
wsAddr: string;
|
||||
}
|
||||
|
||||
export interface IUserState {
|
||||
token: string;
|
||||
username: string;
|
||||
@@ -42,7 +48,7 @@ export interface IUserState {
|
||||
avatar: string;
|
||||
permissions: any[];
|
||||
info: UserInfoState | null;
|
||||
config: any;
|
||||
config: ConfigState | null;
|
||||
}
|
||||
|
||||
export const useUserStore = defineStore({
|
||||
@@ -75,7 +81,7 @@ export const useUserStore = defineStore({
|
||||
getUserInfo(): UserInfoState | null {
|
||||
return this.info;
|
||||
},
|
||||
getConfig(): object {
|
||||
getConfig(): ConfigState | null {
|
||||
return this.config;
|
||||
},
|
||||
},
|
||||
@@ -98,7 +104,7 @@ export const useUserStore = defineStore({
|
||||
setUserInfo(info: UserInfoState | null) {
|
||||
this.info = info;
|
||||
},
|
||||
setConfig(config) {
|
||||
setConfig(config: ConfigState | null) {
|
||||
this.config = config;
|
||||
},
|
||||
// 登录
|
||||
|
17
web/src/utils/icons.ts
Normal file
17
web/src/utils/icons.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Component } from 'vue';
|
||||
import { renderIcon } from '@/utils/index';
|
||||
import * as antdIcons from '@vicons/antd';
|
||||
// import * as x5Icons from '@vicons/ionicons5';
|
||||
|
||||
export const Icons = {};
|
||||
for (const element of Object.keys(antdIcons)) {
|
||||
Icons[element] = renderIcon(antdIcons[element]);
|
||||
}
|
||||
|
||||
// for (const element of Object.keys(x5Icons)) {
|
||||
// constantRouterIcon[element] = renderIcon(x5Icons[element]);
|
||||
// }
|
||||
|
||||
export function getIconComponent(name: string): Component {
|
||||
return Icons[name];
|
||||
}
|
@@ -15,8 +15,8 @@ export const renderTooltip = (trigger, content) => {
|
||||
/**
|
||||
* render 图标
|
||||
* */
|
||||
export function renderIcon(icon) {
|
||||
return () => h(NIcon, null, { default: () => h(icon) });
|
||||
export function renderIcon(icon, props = null) {
|
||||
return () => h(NIcon, props, { default: () => h(icon) });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -138,3 +138,7 @@ export function isNullOrUnDef(val: unknown): val is null | undefined {
|
||||
export function isLetterBegin(str) {
|
||||
return /^[A-z]/.test(str);
|
||||
}
|
||||
|
||||
export function isUrl(url: string): boolean {
|
||||
return /(^http|https:\/\/)/g.test(url);
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ import { SocketEnum } from '@/enums/socketEnum';
|
||||
import { notificationStoreWidthOut } from '@/store/modules/notification';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import { TABS_ROUTES } from '@/store/mutation-types';
|
||||
import { MessageRow } from '@/enums/systemMessageEnum';
|
||||
import { isJsonString } from '@/utils/is';
|
||||
|
||||
let socket: WebSocket;
|
||||
@@ -103,7 +102,7 @@ export default (onMessage: Function) => {
|
||||
if (useUserStore.token === '') {
|
||||
throw new Error('用户未登录,稍后重试...');
|
||||
}
|
||||
socket = new WebSocket(useUserStore.config.wsAddr + '?authorization=' + useUserStore.token);
|
||||
socket = new WebSocket(useUserStore.config?.wsAddr + '?authorization=' + useUserStore.token);
|
||||
init();
|
||||
} catch (e) {
|
||||
console.log('createSocket err:' + e);
|
||||
|
@@ -22,7 +22,7 @@
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="文档地址">
|
||||
<div class="flex items-center">
|
||||
<a href="https://github.com/bufanyun/hotgo" class="py-2" target="_blank"
|
||||
<a href="https://github.com/bufanyun/hotgo/tree/v2.0/docs" class="py-2" target="_blank"
|
||||
>查看文档地址</a
|
||||
>
|
||||
</div>
|
||||
|
74
web/src/views/addons/hgexample/config/BasicSetting.vue
Normal file
74
web/src/views/addons/hgexample/config/BasicSetting.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="测试参数" path="basicTest">
|
||||
<n-input v-model:value="formValue.basicTest" placeholder="请输入测试参数" />
|
||||
<template #feedback>
|
||||
这是一个测试参数,每个插件都可以有独立的配置项,可以按需添加</template
|
||||
>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { getConfig, updateConfig } from '@/api/addons/hgexample/config';
|
||||
|
||||
const group = ref('basic');
|
||||
|
||||
const show = ref(false);
|
||||
const rules = {
|
||||
basicTest: {
|
||||
required: true,
|
||||
message: '请输入测试参数',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
|
||||
const formValue = ref({
|
||||
basicTest: 'HotGo',
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
updateConfig({ group: group.value, list: formValue.value }).then((_res) => {
|
||||
message.success('更新成功');
|
||||
load();
|
||||
});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load();
|
||||
});
|
||||
|
||||
function load() {
|
||||
show.value = true;
|
||||
new Promise((_resolve, _reject) => {
|
||||
getConfig({ group: group.value })
|
||||
.then((res) => {
|
||||
formValue.value = res.list;
|
||||
})
|
||||
.finally(() => {
|
||||
show.value = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
82
web/src/views/addons/hgexample/config/system.vue
Normal file
82
web/src/views/addons/hgexample/config/system.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-grid cols="24 300:1 600:24" :x-gap="24">
|
||||
<n-grid-item span="6">
|
||||
<n-card :bordered="false" size="small" class="proCard">
|
||||
<n-thing
|
||||
class="thing-cell"
|
||||
v-for="item in typeTabList"
|
||||
:key="item.key"
|
||||
:class="{ 'thing-cell-on': type === item.key }"
|
||||
@click="switchType(item)"
|
||||
>
|
||||
<template #header>{{ item.name }}</template>
|
||||
<template #description>{{ item.desc }}</template>
|
||||
</n-thing>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item span="18">
|
||||
<n-card :bordered="false" size="small" :title="typeTitle" class="proCard">
|
||||
<BasicSetting v-if="type === 1" />
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import BasicSetting from './BasicSetting.vue';
|
||||
const typeTabList = [
|
||||
{
|
||||
name: '基本设置',
|
||||
desc: '系统常规设置',
|
||||
key: 1,
|
||||
},
|
||||
];
|
||||
export default defineComponent({
|
||||
components: {
|
||||
BasicSetting,
|
||||
},
|
||||
setup() {
|
||||
const state = reactive({
|
||||
type: 1,
|
||||
typeTitle: '基本设置',
|
||||
});
|
||||
|
||||
function switchType(e) {
|
||||
state.type = e.key;
|
||||
state.typeTitle = e.name;
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
switchType,
|
||||
typeTabList,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.thing-cell {
|
||||
margin: 0 -16px 10px;
|
||||
padding: 5px 16px;
|
||||
|
||||
&:hover {
|
||||
background: #f3f3f3;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.thing-cell-on {
|
||||
background: #f0faff;
|
||||
color: #2d8cf0;
|
||||
|
||||
::v-deep(.n-thing-main .n-thing-header .n-thing-header__title) {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f0faff;
|
||||
}
|
||||
}
|
||||
</style>
|
45
web/src/views/addons/hgexample/portal/form.vue
Normal file
45
web/src/views/addons/hgexample/portal/form.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<n-form class="py-4">
|
||||
<n-form-item label="测试入口" path="index">
|
||||
<n-input-group>
|
||||
<n-input placeholder="请输入" :default-value="url" :disabled="true" />
|
||||
<n-button v-copy="url" type="primary" @click="copy"> 复制链接 </n-button>
|
||||
</n-input-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="二维码" path="index">
|
||||
<div class="text-center">
|
||||
<qrcode-vue :value="url" :size="220" class="canvas" style="margin: 0 auto" />
|
||||
</div>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import QrcodeVue from 'qrcode.vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
|
||||
const message = useMessage();
|
||||
|
||||
interface Props {
|
||||
path: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
path: '',
|
||||
});
|
||||
|
||||
const copy = () => {
|
||||
message.success('复制成功');
|
||||
};
|
||||
|
||||
const useUserStore = useUserStoreWidthOut();
|
||||
const url = useUserStore.config?.domain + props.path;
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep(.card-tabs .n-tabs-nav--bar-type) {
|
||||
padding-left: 4px;
|
||||
}
|
||||
</style>
|
30
web/src/views/addons/hgexample/portal/index.vue
Normal file
30
web/src/views/addons/hgexample/portal/index.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-card title="应用入口" style="margin-bottom: 16px">
|
||||
<n-tabs type="line" animated>
|
||||
<n-tab-pane name="admin" tab="后台API">
|
||||
<Form path="/admin/hgexample/index/test?name=HotGo" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="api" tab="前台API">
|
||||
<Form path="/api/hgexample/index/test?name=HotGo" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="home" tab="前台页面">
|
||||
<Form path="/home/hgexample/index/test?name=HotGo" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="websocket" tab="Websocket">
|
||||
<Form path="/socket/hgexample/index/test?name=HotGo" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import Form from './form.vue';
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep(.card-tabs .n-tabs-nav--bar-type) {
|
||||
padding-left: 4px;
|
||||
}
|
||||
</style>
|
@@ -152,7 +152,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, computed, watch } from 'vue';
|
||||
import { rules, options, State, newState } from './model';
|
||||
import { Edit, MaxSort } from '@/api/test';
|
||||
import { Edit, MaxSort } from '@/api/addons/hgexample/table';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
import DatePicker from '@/components/DatePicker/datePicker.vue';
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="普通表格演示">
|
||||
<n-card :bordered="false" title="表格例子">
|
||||
这里提供了一些常用的普通表格组件的用法和表单组件的例子,你可能会需要
|
||||
</n-card>
|
||||
</div>
|
||||
@@ -77,7 +77,7 @@
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
import { Delete, List, Status, Export } from '@/api/test';
|
||||
import { Delete, List, Status, Export } from '@/api/addons/hgexample/table';
|
||||
import { State, columns, schemas, options, newState } from './model';
|
||||
import { DeleteOutlined, PlusOutlined, ExportOutlined } from '@vicons/antd';
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -186,7 +186,7 @@
|
||||
}
|
||||
|
||||
function handleView(record: Recordable) {
|
||||
router.push({ name: 'test_view', params: { id: record.id } });
|
||||
router.push({ name: 'table_view', params: { id: record.id } });
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
@@ -3,7 +3,7 @@ import { NAvatar, NImage, NTag, NSwitch, NRate } from 'naive-ui';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { Dicts } from '@/api/dict/dict';
|
||||
import { Switch } from '@/api/test';
|
||||
import { Switch } from '@/api/addons/hgexample/table';
|
||||
import { isNullObject } from '@/utils/is';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
||||
import { defRangeShortcuts, defShortcuts, formatToDate } from '@/utils/dateUtil';
|
@@ -109,7 +109,7 @@
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { View } from '@/api/test';
|
||||
import { View } from '@/api/addons/hgexample/table';
|
||||
import { newState, options } from './model';
|
||||
import { getOptionLabel, getOptionTag } from '@/utils/hotgo';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
@@ -3,7 +3,6 @@ import { NTag } from 'naive-ui';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { getOptionLabel, getOptionTag, Options } from '@/utils/hotgo';
|
||||
import { Dicts } from '@/api/dict/dict';
|
||||
import { schemas } from '@/views/test/model';
|
||||
import { isNullObject } from '@/utils/is';
|
||||
|
||||
export const listColumns = [
|
||||
@@ -100,18 +99,3 @@ export function newState(state: State | null): State {
|
||||
export const options = ref<Options>({
|
||||
sys_normal_disable: [],
|
||||
});
|
||||
|
||||
async function loadOptions() {
|
||||
options.value = await Dicts({
|
||||
types: ['sys_normal_disable'],
|
||||
});
|
||||
for (const item of schemas.value) {
|
||||
switch (item.field) {
|
||||
case 'status':
|
||||
item.componentProps.options = options.value.sys_normal_disable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await loadOptions();
|
||||
|
@@ -87,7 +87,8 @@
|
||||
<template v-else>
|
||||
<div class="text-sn"> 总激活卡板: </div>
|
||||
<div class="text-sn">
|
||||
<CountTo :startVal="1" :endVal="saleroom.amount" /> <!-- prefix="¥"-->
|
||||
<CountTo :startVal="1" :endVal="saleroom.amount" />
|
||||
<!-- prefix="¥"-->
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -325,7 +326,6 @@
|
||||
|
||||
onMounted(async () => {
|
||||
const data = await getConsoleInfo();
|
||||
console.log('data:'+JSON.stringify(data))
|
||||
visits.value = data.visits;
|
||||
saleroom.value = data.saleroom;
|
||||
orderLarge.value = data.orderLarge;
|
||||
|
23
web/src/views/develop/addons/components/model.ts
Normal file
23
web/src/views/develop/addons/components/model.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
export const genInfoObj = {
|
||||
label: '',
|
||||
name: '',
|
||||
group: 1,
|
||||
version: 'v1.0.0',
|
||||
brief: '',
|
||||
description: '',
|
||||
author: '',
|
||||
};
|
||||
|
||||
export const selectListObj = {
|
||||
groupType: [],
|
||||
status: [],
|
||||
};
|
||||
|
||||
export function newState(state) {
|
||||
if (state !== null) {
|
||||
return cloneDeep(state);
|
||||
}
|
||||
return cloneDeep(genInfoObj);
|
||||
}
|
502
web/src/views/develop/addons/index.vue
Normal file
502
web/src/views/develop/addons/index.vue
Normal file
@@ -0,0 +1,502 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="插件管理">
|
||||
在这里可以管理和创建插件模板,开发独立、临时性、工具类型的功能时推荐使用插件化开发。
|
||||
</n-card>
|
||||
</div>
|
||||
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<BasicForm
|
||||
@register="register"
|
||||
@submit="handleSubmit"
|
||||
@reset="handleReset"
|
||||
ref="searchFormRef"
|
||||
>
|
||||
<template #statusSlot="{ model, field }">
|
||||
<n-input v-model:value="model[field]" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1090"
|
||||
>
|
||||
<template #tableTitle>
|
||||
<n-button type="primary" @click="addTable">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
创建新插件
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
title="创建新插件"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<n-alert :show-icon="false" type="info">
|
||||
注意:插件创建成功后会在服务端对应的项目目录中创建插件模块,并自动注册到当前项目中。
|
||||
</n-alert>
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-placement="left"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="插件标签" path="label">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.label" />
|
||||
<template #feedback>显示在插件列表中的标识. 不要超过20个字符</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="插件包名" path="name">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.name" />
|
||||
<template #feedback>
|
||||
系统按照此名称创建和查找插件定义, 只能英文和下划线组成,建议全部小写,例如:hgexample
|
||||
</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="功能分组" path="group">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.groupType"
|
||||
v-model:value="formParams.group"
|
||||
:on-update:value="onUpdateValueGroup"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="版本" path="version">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.version" />
|
||||
<template #feedback>此版本号用于插件的版本更新</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="简介" path="brief">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.brief" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="使用说明" path="description">
|
||||
<n-input
|
||||
type="textarea"
|
||||
placeholder="使用说明"
|
||||
v-model:value="formParams.description"
|
||||
/>
|
||||
<template #feedback>详细介绍插件的功能和使用方法</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="作者" path="author">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.author" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="() => (showModal = false)">取消</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">确认创建</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, onBeforeMount, reactive, ref } from 'vue';
|
||||
import {
|
||||
NIcon,
|
||||
NTag,
|
||||
NIconWrapper,
|
||||
useMessage,
|
||||
NImage,
|
||||
useDialog,
|
||||
useNotification,
|
||||
} from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
import { List, Selects, Build, UnInstall, Install, Upgrade } from '@/api/develop/addons';
|
||||
import { PlusOutlined } from '@vicons/antd';
|
||||
import { newState } from '@/views/develop/addons/components/model';
|
||||
import { errorImg } from '@/utils/hotgo';
|
||||
import { isUrl } from '@/utils/is';
|
||||
import { getIconComponent } from '@/utils/icons';
|
||||
|
||||
const selectList = ref({
|
||||
groupType: [],
|
||||
status: [],
|
||||
});
|
||||
const columns = [
|
||||
{
|
||||
title: '图标',
|
||||
key: 'logo',
|
||||
width: 80,
|
||||
render(row) {
|
||||
if (isUrl(row.logo)) {
|
||||
return h(NImage, {
|
||||
width: 48,
|
||||
height: 48,
|
||||
src: row.logo,
|
||||
onError: errorImg,
|
||||
style: {
|
||||
width: '48px',
|
||||
height: '48px',
|
||||
'max-width': '100%',
|
||||
'max-height': '100%',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return h(
|
||||
NIconWrapper,
|
||||
{
|
||||
size: 48,
|
||||
borderRadius: 8,
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
NIcon,
|
||||
{
|
||||
size: 36,
|
||||
style: {
|
||||
marginTop: '-8px',
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => h(getIconComponent(row.logo)),
|
||||
}
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '模块名称',
|
||||
key: 'name',
|
||||
width: 120,
|
||||
render(row) {
|
||||
return h('div', {
|
||||
innerHTML:
|
||||
'<div >' + row.label + '<br><span style="opacity: 0.8;">' + row.name + '</span></div>',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '作者',
|
||||
key: 'author',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '分组',
|
||||
key: 'groupName',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: 'info',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.groupName,
|
||||
}
|
||||
);
|
||||
},
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '简介',
|
||||
key: 'brief',
|
||||
render(row) {
|
||||
return row.brief;
|
||||
},
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '详细描述',
|
||||
key: 'description',
|
||||
width: 300,
|
||||
render(row) {
|
||||
return h('p', { id: 'app' }, [
|
||||
h('div', {
|
||||
innerHTML: '<div style="white-space: pre-wrap">' + row.description + '</div>',
|
||||
}),
|
||||
]);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '版本',
|
||||
key: 'version',
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
|
||||
const checkedIds = ref([]);
|
||||
const searchFormRef = ref<any>();
|
||||
|
||||
const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'name',
|
||||
component: 'NInput',
|
||||
label: '模块名称',
|
||||
componentProps: {
|
||||
placeholder: '请输入模块名称或标签',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'group',
|
||||
component: 'NSelect',
|
||||
label: '分组',
|
||||
componentProps: {
|
||||
placeholder: '请选择分组',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '安装状态',
|
||||
componentProps: {
|
||||
placeholder: '请选择状态',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const notification = useNotification();
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
const formParams = ref<any>();
|
||||
|
||||
const rules = {};
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
// fixed: 'right',
|
||||
render(record) {
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
{
|
||||
label: '安装模块',
|
||||
onClick: handleInstall.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.installStatus !== 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'warning',
|
||||
label: '更新配置',
|
||||
onClick: handleUpgrade.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.installStatus === 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'error',
|
||||
label: '卸载模块',
|
||||
onClick: handleUnInstall.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.installStatus === 1;
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 80,
|
||||
schemas,
|
||||
});
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
mapWidth();
|
||||
return await List({ ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function reloadTable() {
|
||||
actionRef.value.reload();
|
||||
}
|
||||
|
||||
function handleInstall(record: Recordable) {
|
||||
dialog.info({
|
||||
title: '提示',
|
||||
content: '你确定要安装 【' + record.label + '】 模块?安装成功后需要重启服务才能生效!',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Install(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleUpgrade(record: Recordable) {
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '你确定要更新 【' + record.label + '】 模块?更新成功后需要重启服务才能生效!',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Upgrade(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleUnInstall(record: Recordable) {
|
||||
dialog.error({
|
||||
title: '提示',
|
||||
content: '你确定要卸载 【' + record.label + '】 模块?卸载成功后需要重启服务才能生效!',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
UnInstall(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleSubmit(_values: Recordable) {
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function handleReset(_values: Recordable) {
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function addTable() {
|
||||
showModal.value = true;
|
||||
formParams.value = newState(null);
|
||||
}
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Build(formParams.value).then((_res) => {
|
||||
showModal.value = false;
|
||||
buildSuccessNotify();
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
const dialogWidth = ref('50%');
|
||||
|
||||
function mapWidth() {
|
||||
let val = document.body.clientWidth;
|
||||
const def = 840; // 默认宽度
|
||||
if (val < def) {
|
||||
dialogWidth.value = '100%';
|
||||
} else {
|
||||
dialogWidth.value = def + 'px';
|
||||
}
|
||||
|
||||
return dialogWidth.value;
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await loadSelect();
|
||||
});
|
||||
|
||||
const loadSelect = async () => {
|
||||
selectList.value = await Selects({});
|
||||
for (const item of schemas.value) {
|
||||
switch (item.field) {
|
||||
case 'status':
|
||||
item.componentProps.options = selectList.value.status;
|
||||
break;
|
||||
case 'group':
|
||||
item.componentProps.options = selectList.value.groupType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onUpdateValueGroup(value) {
|
||||
formParams.value.group = value;
|
||||
}
|
||||
|
||||
function buildSuccessNotify() {
|
||||
let count = 10;
|
||||
const n = notification.success({
|
||||
title: '插件构建成功',
|
||||
content: `如果你使用的热编译,页面将在 ${count} 秒后自动刷新插件列表即可生效。否则请手动重启服务后刷新页面!`,
|
||||
duration: 10000,
|
||||
closable: false,
|
||||
onAfterEnter: () => {
|
||||
const minusCount = () => {
|
||||
count--;
|
||||
n.content = `如果你使用的热编译,页面将在 ${count} 秒后自动刷新插件列表即可生效。否则请手动重启服务后刷新页面!`;
|
||||
if (count > 0) {
|
||||
window.setTimeout(minusCount, 1000);
|
||||
}
|
||||
};
|
||||
window.setTimeout(minusCount, 1000);
|
||||
},
|
||||
onAfterLeave: () => {
|
||||
location.reload();
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
@@ -1,306 +1,311 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-card
|
||||
:bordered="true"
|
||||
title="基本设置"
|
||||
class="proCard mt-2"
|
||||
size="small"
|
||||
:segmented="{ content: true }"
|
||||
>
|
||||
<n-form ref="formRef" :model="formValue">
|
||||
<n-row :gutter="24">
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="生成类型" path="title">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.genType"
|
||||
v-model:value="formValue.genType"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="实体命名" path="varName">
|
||||
<n-input placeholder="请输入" v-model:value="formValue.varName" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item
|
||||
label="数据库"
|
||||
path="dbName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.db"
|
||||
v-model:value="formValue.dbName"
|
||||
@update:value="handleDbUpdateValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item
|
||||
label="数据库表"
|
||||
path="tableName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="tablesOption"
|
||||
v-model:value="formValue.tableName"
|
||||
@update:value="handleTableUpdateValue"
|
||||
:disabled="formValue.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="18">
|
||||
<n-form-item
|
||||
label="表格头部按钮组"
|
||||
path="tableName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.headOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="add" label="新增表单按钮" />
|
||||
<n-checkbox value="batchDel" label="批量删除按钮" />
|
||||
<n-checkbox value="export" label="导出按钮" />
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="24">
|
||||
<n-form-item
|
||||
label="表格列操作"
|
||||
path="columnOps"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.columnOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="edit" label="编辑" />
|
||||
<n-checkbox value="status" label="状态修改" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>主表中存在`status`字段时才会生效</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="del" label="删除" />
|
||||
<n-checkbox value="view" label="详情页" />
|
||||
<n-checkbox value="check" label="开启勾选列" />
|
||||
<n-checkbox value="switch" label="操作开关" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>主表中存在`switch`字段时才会生效</span>
|
||||
</n-popover>
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="24">
|
||||
<n-form-item
|
||||
label="自动化操作"
|
||||
path="autoOps"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.autoOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="genMenuPermissions" label="生成菜单权限" />
|
||||
<n-checkbox value="runDao" label="生成前运行 [gf gen dao]" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>请确保运行环境已安装gf命令</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="runService" label="生成后运行 [gf gen service]" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>请确保运行环境已安装gf命令</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="forcedCover" label="强制覆盖" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>只会强制覆盖需要生成的文件,但不包含SQL文件</span>
|
||||
</n-popover>
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="上级菜单" path="pid">
|
||||
<n-tree-select
|
||||
:options="optionMenuTree"
|
||||
:value="formValue.options.menu.pid"
|
||||
@update:value="handleUpdateMenuPid"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单名称" path="tableComment">
|
||||
<n-input placeholder="请输入" v-model:value="formValue.tableComment" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单图标" path="menuIcon">
|
||||
<IconSelector style="width: 100%" v-model:value="formValue.options.menu.icon" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单排序" path="menuIcon">
|
||||
<n-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.options.menu.sort"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card
|
||||
:bordered="true"
|
||||
title="关联表设置"
|
||||
class="proCard mt-2"
|
||||
size="small"
|
||||
:segmented="{ content: true }"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-space>
|
||||
<n-button type="warning" @click="addJoin" :disabled="formValue.options?.join?.length >= 3"
|
||||
>新增关联表</n-button
|
||||
>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<n-form ref="formRef" :model="formValue">
|
||||
<n-alert :show-icon="false">关联表数量建议在三个以下</n-alert>
|
||||
|
||||
<n-row :gutter="6" v-for="(join, index) in formValue.options.join" :key="index">
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="关联表" path="join.linkTable">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="linkTablesOption"
|
||||
v-model:value="join.linkTable"
|
||||
@update:value="handleLinkTableUpdateValue(join)"
|
||||
:disabled="formValue.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="3" style="min-width: 100px">
|
||||
<n-form-item
|
||||
label="别名"
|
||||
path="join.alias"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-input
|
||||
placeholder="请输入"
|
||||
v-model:value="join.alias"
|
||||
@update:value="updateJoinAlias"
|
||||
/>
|
||||
|
||||
<template #feedback> {{ joinAliasFeedback }}</template>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="3" style="min-width: 100px">
|
||||
<n-form-item label="关联方式" path="join.linkMode">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.linkMode"
|
||||
v-model:value="join.linkMode"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
<n-col :span="5" style="min-width: 180px">
|
||||
<n-form-item label="关联字段" path="join.field">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="linkColumnsLoading"
|
||||
placeholder="请选择"
|
||||
:options="linkColumnsOption[join.uuid]"
|
||||
v-model:value="join.field"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="5" style="min-width: 180px">
|
||||
<n-form-item label="主表关联字段" path="join.masterField">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="columnsLoading"
|
||||
placeholder="请选择"
|
||||
:options="columnsOption"
|
||||
v-model:value="join.masterField"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="2" style="min-width: 50px">
|
||||
<n-space>
|
||||
<n-form-item label="操作" path="title">
|
||||
<n-button @click="delJoin(join, index)" size="small" strong secondary type="error"
|
||||
>移除</n-button
|
||||
>
|
||||
<n-spin :show="bodyShow" description="请稍候...">
|
||||
<n-card
|
||||
:bordered="true"
|
||||
title="基本设置"
|
||||
class="proCard mt-2"
|
||||
size="small"
|
||||
:segmented="{ content: true }"
|
||||
>
|
||||
<n-form ref="formRef" :model="formValue">
|
||||
<n-row :gutter="24">
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="生成类型" path="title">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.genType"
|
||||
v-model:value="formValue.genType"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-space>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="实体命名" path="varName">
|
||||
<n-input placeholder="请输入" v-model:value="formValue.varName" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item
|
||||
label="数据库"
|
||||
path="dbName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.db"
|
||||
v-model:value="formValue.dbName"
|
||||
@update:value="handleDbUpdateValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item
|
||||
label="数据库表"
|
||||
path="tableName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="tablesOption"
|
||||
v-model:value="formValue.tableName"
|
||||
@update:value="handleTableUpdateValue"
|
||||
:disabled="formValue.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="18">
|
||||
<n-form-item
|
||||
label="表格头部按钮组"
|
||||
path="tableName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.headOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="add" label="新增表单按钮" />
|
||||
<n-checkbox value="batchDel" label="批量删除按钮" />
|
||||
<n-checkbox value="export" label="导出按钮" />
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="24">
|
||||
<n-form-item
|
||||
label="表格列操作"
|
||||
path="columnOps"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.columnOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="edit" label="编辑" />
|
||||
<n-checkbox value="status" label="状态修改" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>主表中存在`status`字段时才会生效</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="del" label="删除" />
|
||||
<n-checkbox value="view" label="详情页" />
|
||||
<n-checkbox value="check" label="开启勾选列" />
|
||||
<n-checkbox value="switch" label="操作开关" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>主表中存在`switch`字段时才会生效</span>
|
||||
</n-popover>
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="24">
|
||||
<n-form-item
|
||||
label="自动化操作"
|
||||
path="autoOps"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.autoOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="genMenuPermissions" label="生成菜单权限" />
|
||||
<n-checkbox value="runDao" label="生成前运行 [gf gen dao]" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>如果你选择的表已经生成过dao相关代码,可以忽略</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="runService" label="生成后运行 [gf gen service]" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>如果是插件模块,勾选后也会自动在对应插件下运行service相关代码生成</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="forcedCover" label="强制覆盖" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>只会强制覆盖需要生成的文件,但不包含SQL文件</span>
|
||||
</n-popover>
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="上级菜单" path="pid">
|
||||
<n-tree-select
|
||||
:options="optionMenuTree"
|
||||
:value="formValue.options.menu.pid"
|
||||
@update:value="handleUpdateMenuPid"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单名称" path="tableComment">
|
||||
<n-input placeholder="请输入" v-model:value="formValue.tableComment" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单图标" path="menuIcon">
|
||||
<IconSelector style="width: 100%" v-model:value="formValue.options.menu.icon" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单排序" path="menuIcon">
|
||||
<n-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.options.menu.sort"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card
|
||||
:bordered="true"
|
||||
title="关联表设置"
|
||||
class="proCard mt-2"
|
||||
size="small"
|
||||
:segmented="{ content: true }"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-space>
|
||||
<n-button
|
||||
type="warning"
|
||||
@click="addJoin"
|
||||
:disabled="formValue.options?.join?.length >= 3"
|
||||
>新增关联表</n-button
|
||||
>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<n-form ref="formRef" :model="formValue">
|
||||
<n-alert :show-icon="false">关联表数量建议在三个以下</n-alert>
|
||||
|
||||
<n-row :gutter="6" v-for="(join, index) in formValue.options.join" :key="index">
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="关联表" path="join.linkTable">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="linkTablesOption"
|
||||
v-model:value="join.linkTable"
|
||||
@update:value="handleLinkTableUpdateValue(join)"
|
||||
:disabled="formValue.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="3" style="min-width: 100px">
|
||||
<n-form-item
|
||||
label="别名"
|
||||
path="join.alias"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-input
|
||||
placeholder="请输入"
|
||||
v-model:value="join.alias"
|
||||
@update:value="updateJoinAlias"
|
||||
/>
|
||||
|
||||
<template #feedback> {{ joinAliasFeedback }}</template>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="3" style="min-width: 100px">
|
||||
<n-form-item label="关联方式" path="join.linkMode">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.linkMode"
|
||||
v-model:value="join.linkMode"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
<n-col :span="5" style="min-width: 180px">
|
||||
<n-form-item label="关联字段" path="join.field">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="linkColumnsLoading"
|
||||
placeholder="请选择"
|
||||
:options="linkColumnsOption[join.uuid]"
|
||||
v-model:value="join.field"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="5" style="min-width: 180px">
|
||||
<n-form-item label="主表关联字段" path="join.masterField">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="columnsLoading"
|
||||
placeholder="请选择"
|
||||
:options="columnsOption"
|
||||
v-model:value="join.masterField"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="2" style="min-width: 50px">
|
||||
<n-space>
|
||||
<n-form-item label="操作" path="title">
|
||||
<n-button @click="delJoin(join, index)" size="small" strong secondary type="error"
|
||||
>移除</n-button
|
||||
>
|
||||
</n-form-item>
|
||||
</n-space>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -316,7 +321,9 @@
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { isLetterBegin } from '@/utils/is';
|
||||
|
||||
const timer = ref();
|
||||
const formRef = ref<FormInst | null>(null);
|
||||
const bodyShow = ref(true);
|
||||
const tablesLoading = ref(false);
|
||||
const columnsLoading = ref(false);
|
||||
const linkColumnsLoading = ref(false);
|
||||
@@ -364,12 +371,16 @@
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(async function () {
|
||||
await instLoad();
|
||||
// 切换tab时会导致选项被清空,这里重新进行加载
|
||||
await loadLinkColumnsOption();
|
||||
await loadMenuTreeOption();
|
||||
}, 500);
|
||||
timer.value = setInterval(async () => {
|
||||
if (props.value.id > 0) {
|
||||
clearTimeout(timer.value);
|
||||
await instLoad();
|
||||
// 切换tab时会导致选项被清空,这里重新进行加载
|
||||
await loadLinkColumnsOption();
|
||||
await loadMenuTreeOption();
|
||||
bodyShow.value = false;
|
||||
}
|
||||
}, 30);
|
||||
});
|
||||
|
||||
const loadMenuTreeOption = async () => {
|
||||
|
@@ -38,6 +38,7 @@ export const genInfoObj = {
|
||||
tableComment: '',
|
||||
daoName: '',
|
||||
masterColumns: [],
|
||||
addonName: null,
|
||||
status: 2,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
|
@@ -82,7 +82,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { useDialog, useMessage, useNotification } from 'naive-ui';
|
||||
import BaseInfo from './components/BaseInfo.vue';
|
||||
import EditMasterCell from './components/EditMasterCell.vue';
|
||||
import EditSlaveCell from './components/EditSlaveCell.vue';
|
||||
@@ -110,6 +110,7 @@
|
||||
const formBtnLoading = ref(false);
|
||||
const previewModel = ref<any>();
|
||||
const dialog = useDialog();
|
||||
const notification = useNotification();
|
||||
|
||||
onMounted(async () => {
|
||||
if (genId < 1 && props.genId < 1) {
|
||||
@@ -181,15 +182,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function _handleSlaveClose(name: string) {
|
||||
const nameIndex = panels.value.findIndex((panelName) => panelName === name);
|
||||
if (!~nameIndex) return;
|
||||
panels.value.splice(nameIndex, 1);
|
||||
if (name === value.value) {
|
||||
value.value = panels.value[Math.min(nameIndex, panels.value.length - 1)];
|
||||
}
|
||||
}
|
||||
|
||||
function handleClose(name: string) {
|
||||
const nameIndex = panels.value.findIndex((panelName) => panelName === name);
|
||||
if (!~nameIndex) return;
|
||||
@@ -218,10 +210,7 @@
|
||||
formBtnLoading.value = true;
|
||||
Build(genInfo.value)
|
||||
.then((_res) => {
|
||||
setTimeout(function () {
|
||||
location.reload();
|
||||
}, 1500);
|
||||
message.success('生成提交成功,即将刷新页面..');
|
||||
buildSuccessNotify();
|
||||
})
|
||||
.finally(() => {
|
||||
formBtnLoading.value = false;
|
||||
@@ -249,6 +238,29 @@
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function buildSuccessNotify() {
|
||||
let count = 6;
|
||||
const n = notification.success({
|
||||
title: '生成提交成功',
|
||||
content: `如果你使用的热编译,页面将在 ${count} 秒后自动刷新即可生效。否则请手动重启服务后刷新页面!`,
|
||||
duration: 6000,
|
||||
closable: false,
|
||||
onAfterEnter: () => {
|
||||
const minusCount = () => {
|
||||
count--;
|
||||
n.content = `如果你使用的热编译,页面将在 ${count} 秒后自动刷新即可生效。否则请手动重启服务后刷新页面!`;
|
||||
if (count > 0) {
|
||||
window.setTimeout(minusCount, 1000);
|
||||
}
|
||||
};
|
||||
window.setTimeout(minusCount, 1000);
|
||||
},
|
||||
onAfterLeave: () => {
|
||||
location.reload();
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
::v-deep(.alert-margin) {
|
||||
|
@@ -1,130 +1,145 @@
|
||||
<template>
|
||||
<n-card :bordered="false" class="proCard" title="代码生成">
|
||||
<!-- <n-card :bordered="false" title="代码生成"> 你可以在这里查看到平台所有的短信发送记录。 </n-card>-->
|
||||
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" ref="searchFormRef">
|
||||
<template #statusSlot="{ model, field }">
|
||||
<n-input v-model:value="model[field]" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1090"
|
||||
>
|
||||
<template #tableTitle>
|
||||
<n-button type="primary" @click="addTable">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
立即生成
|
||||
</n-button>
|
||||
|
||||
<n-button type="error" @click="batchDelete" :disabled="batchDeleteDisabled">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
批量删除
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
title="立即生成"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<!-- <n-alert :show-icon="false" type="info">-->
|
||||
<!-- 注意:!-->
|
||||
<!-- </n-alert>-->
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-placement="left"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
<div>
|
||||
<n-card :bordered="false" class="proCard" title="代码生成">
|
||||
<BasicForm
|
||||
@register="register"
|
||||
@submit="handleSubmit"
|
||||
@reset="handleReset"
|
||||
ref="searchFormRef"
|
||||
>
|
||||
<n-form-item label="生成类型" path="genType">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.genType"
|
||||
v-model:value="formParams.genType"
|
||||
:on-update:value="onUpdateValueGenType"
|
||||
/>
|
||||
</n-form-item>
|
||||
<template #statusSlot="{ model, field }">
|
||||
<n-input v-model:value="model[field]" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
|
||||
<n-form-item label="生成模板" path="genTemplate">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="genTemplateOptions"
|
||||
v-model:value="formParams.genTemplate"
|
||||
:onFocus="onFocusGenTemplate"
|
||||
/>
|
||||
</n-form-item>
|
||||
<BasicTable
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1090"
|
||||
>
|
||||
<template #tableTitle>
|
||||
<n-button type="primary" @click="addTable">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
立即生成
|
||||
</n-button>
|
||||
|
||||
<n-button type="error" @click="batchDelete" :disabled="batchDeleteDisabled">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
批量删除
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<n-form-item
|
||||
label="数据库"
|
||||
path="dbName"
|
||||
v-if="formParams.genType >= 10 && formParams.genType < 20"
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
title="立即生成"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<!-- <n-alert :show-icon="false" type="info">-->
|
||||
<!-- 注意:!-->
|
||||
<!-- </n-alert>-->
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-placement="left"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.db"
|
||||
v-model:value="formParams.dbName"
|
||||
@update:value="handleDbUpdateValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
label="数据库表"
|
||||
path="tableName"
|
||||
v-if="formParams.genType >= 10 && formParams.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="selectList.tables"
|
||||
v-model:value="formParams.tableName"
|
||||
@update:value="handleTableUpdateValue"
|
||||
:disabled="formParams.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="生成类型" path="genType">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.genType"
|
||||
v-model:value="formParams.genType"
|
||||
:on-update:value="onUpdateValueGenType"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item
|
||||
label="菜单名称"
|
||||
path="tableComment"
|
||||
v-show="formParams.genType >= 10 && formParams.genType < 20"
|
||||
>
|
||||
<n-input placeholder="请输入" v-model:value="formParams.tableComment" />
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
label="数据库"
|
||||
path="dbName"
|
||||
v-if="formParams.genType >= 10 && formParams.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.db"
|
||||
v-model:value="formParams.dbName"
|
||||
@update:value="handleDbUpdateValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
label="数据库表"
|
||||
path="tableName"
|
||||
v-if="formParams.genType >= 10 && formParams.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="selectList.tables"
|
||||
v-model:value="formParams.tableName"
|
||||
@update:value="handleTableUpdateValue"
|
||||
:disabled="formParams.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="实体命名" path="varName">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.varName" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-form-item label="生成模板" path="genTemplate">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="genTemplateOptions"
|
||||
v-model:value="formParams.genTemplate"
|
||||
:onFocus="onFocusGenTemplate"
|
||||
@update:value="handleGenTemplateUpdateValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="() => (showModal = false)">取消</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">生成配置</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</n-card>
|
||||
<n-form-item label="选择插件" path="addonName" v-show="selectAddon">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.addons"
|
||||
v-model:value="formParams.addonName"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item
|
||||
label="菜单名称"
|
||||
path="tableComment"
|
||||
v-show="formParams.genType >= 10 && formParams.genType < 20"
|
||||
>
|
||||
<n-input placeholder="请输入" v-model:value="formParams.tableComment" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="实体命名" path="varName">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.varName" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="() => (showModal = false)">取消</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">生成配置</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -147,75 +162,57 @@
|
||||
formRole: [],
|
||||
dictMode: [],
|
||||
whereMode: [],
|
||||
addons: [],
|
||||
});
|
||||
const columns = [
|
||||
{
|
||||
title: '生成ID',
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
width: 80,
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
title: '生成类型',
|
||||
key: 'genType',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: 'info',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => getOptionLabel(selectList.value.genType, row.genType),
|
||||
}
|
||||
);
|
||||
},
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '生成模板',
|
||||
title: '模板',
|
||||
key: 'genTemplate',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: 'default',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.genTemplateGroup,
|
||||
}
|
||||
);
|
||||
return h('p', { id: 'app' }, [
|
||||
h('div', {
|
||||
innerHTML: '<div><p>' + row.genTemplateGroup + '</p></div>',
|
||||
}),
|
||||
h('div', {
|
||||
innerHTML:
|
||||
'<div><p>' + getOptionLabel(selectList.value.genType, row.genType) + '</p></div>',
|
||||
}),
|
||||
]);
|
||||
},
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '数据库',
|
||||
key: 'dbName',
|
||||
width: 280,
|
||||
render(row) {
|
||||
return h('p', { id: 'app' }, [
|
||||
h('div', {
|
||||
innerHTML: '<div><p>' + row.dbName + '</p></div>',
|
||||
}),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>' + row.tableName + '</p></div>',
|
||||
}),
|
||||
]);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '实体命名',
|
||||
key: 'varName',
|
||||
render(row) {
|
||||
return row.varName;
|
||||
},
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '数据库',
|
||||
key: 'dbName',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '数据表',
|
||||
key: 'tableName',
|
||||
width: 200,
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '菜单名称',
|
||||
key: 'tableComment',
|
||||
width: 200,
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '生成状态',
|
||||
@@ -242,11 +239,6 @@
|
||||
key: 'createdAt',
|
||||
width: 180,
|
||||
},
|
||||
// {
|
||||
// title: '更新时间',
|
||||
// key: 'updatedAt',
|
||||
// width: 180,
|
||||
// },
|
||||
];
|
||||
|
||||
const dialog = useDialog();
|
||||
@@ -409,6 +401,7 @@
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value).then((res) => {
|
||||
@@ -492,6 +485,12 @@
|
||||
formParams.value.genType = value;
|
||||
onFocusGenTemplate();
|
||||
}
|
||||
|
||||
const selectAddon = ref(false);
|
||||
function handleGenTemplateUpdateValue(value, option) {
|
||||
formParams.value.genTemplate = value;
|
||||
selectAddon.value = option.isAddon === true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
@@ -1,61 +1,48 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="支付宝姓名" path="name">
|
||||
<n-input v-model:value="formValue.name" />
|
||||
</n-form-item>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="支付宝姓名" path="name">
|
||||
<n-input v-model:value="formValue.name" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="支付宝账号" path="account ">
|
||||
<n-input v-model:value="formValue.account" />
|
||||
</n-form-item>
|
||||
<n-form-item label="支付宝账号" path="account ">
|
||||
<n-input v-model:value="formValue.account" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="支付宝收款码" path="payeeCode">
|
||||
<UploadImage
|
||||
:maxNumber="1"
|
||||
:helpText="'请上传清晰有效的收款码,图片大小不超过2M'"
|
||||
v-model:value="formValue.payeeCode"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="支付宝收款码" path="payeeCode">
|
||||
<UploadImage
|
||||
:maxNumber="1"
|
||||
:helpText="'请上传清晰有效的收款码,图片大小不超过2M'"
|
||||
v-model:value="formValue.payeeCode"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="登录密码" path="password">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.password"
|
||||
placeholder="请输入登录密码验证身份"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="登录密码" path="password">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.password"
|
||||
placeholder="请输入登录密码验证身份"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref, unref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import UploadImage from '@/components/Upload/uploadImage.vue';
|
||||
import { BasicUpload } from '@/components/Upload';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import { getUserInfo, updateMemberCash } from '@/api/system/user';
|
||||
|
||||
const show = ref(false);
|
||||
const useUserStore = useUserStoreWidthOut();
|
||||
const globSetting = useGlobSetting();
|
||||
const { uploadUrl } = globSetting;
|
||||
const uploadHeaders = reactive({
|
||||
Authorization: useUserStore.token,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
password: {
|
||||
@@ -94,15 +81,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function uploadChange(list: string[]) {
|
||||
// 单图模式,只需要第一个索引
|
||||
if (list.length > 0) {
|
||||
formValue.value.payeeCode = unref(list[0]);
|
||||
} else {
|
||||
formValue.value.payeeCode = unref('');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load();
|
||||
});
|
||||
|
@@ -57,13 +57,21 @@
|
||||
</template>
|
||||
<template #suffix> </template>
|
||||
</n-input>
|
||||
<img
|
||||
style="width: 100px"
|
||||
:src="codeBase64"
|
||||
@click="refreshCode"
|
||||
loading="lazy"
|
||||
alt="点击获取"
|
||||
/>
|
||||
|
||||
<n-loading-bar-provider
|
||||
:to="loadingBarTargetRef"
|
||||
container-style="position: absolute;"
|
||||
>
|
||||
<img
|
||||
ref="loadingBarTargetRef"
|
||||
style="width: 100px"
|
||||
:src="codeBase64"
|
||||
@click="refreshCode"
|
||||
loading="lazy"
|
||||
alt="点击获取"
|
||||
/>
|
||||
<loading-bar-trigger />
|
||||
</n-loading-bar-provider>
|
||||
</n-input-group>
|
||||
</n-form-item>
|
||||
<n-form-item class="default-color">
|
||||
@@ -112,10 +120,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref, onMounted } from 'vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { useMessage, useLoadingBar } from 'naive-ui';
|
||||
import { ResultEnum } from '@/enums/httpEnum';
|
||||
import { PersonOutline, LockClosedOutline, LogoGithub, LogoFacebook } from '@vicons/ionicons5';
|
||||
import { PageEnum } from '@/enums/pageEnum';
|
||||
@@ -136,6 +144,8 @@
|
||||
const loading = ref(false);
|
||||
const autoLogin = ref(true);
|
||||
const codeBase64 = ref('');
|
||||
const loadingBar = useLoadingBar();
|
||||
const loadingBarTargetRef = ref<undefined | HTMLElement>(undefined);
|
||||
const LOGIN_NAME = PageEnum.BASE_LOGIN_NAME;
|
||||
|
||||
const formInline = ref<FormState>({
|
||||
@@ -191,10 +201,12 @@
|
||||
};
|
||||
|
||||
async function refreshCode() {
|
||||
loadingBar.start();
|
||||
const data = await GetCaptcha();
|
||||
codeBase64.value = data.base64;
|
||||
formInline.value.cid = data.cid;
|
||||
formInline.value.code = '';
|
||||
loadingBar.finish();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
@@ -1,48 +1,54 @@
|
||||
<template>
|
||||
<n-card :content-style="{ padding: '10px' }" :header-style="{ padding: '5px' }" :segmented="true">
|
||||
<template #header>
|
||||
<n-skeleton text v-if="loading" width="60%" />
|
||||
<template v-else>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-bold">{{ dataModel.title }}</span>
|
||||
<n-icon style="font-size: 26px">
|
||||
<div v-if="dataModel.iconClass === 'HardwareChip'">
|
||||
<HardwareChip />
|
||||
</div>
|
||||
<div v-else-if="dataModel.iconClass === 'AppsSharp'">
|
||||
<AppsSharp />
|
||||
</div>
|
||||
<div v-else-if="dataModel.iconClass === 'Analytics'">
|
||||
<Analytics />
|
||||
</div>
|
||||
<div v-else-if="dataModel.iconClass === 'PieChart'">
|
||||
<PieChart />
|
||||
</div>
|
||||
<div>
|
||||
<n-card
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<template #header>
|
||||
<n-skeleton text v-if="loading" width="60%" />
|
||||
<template v-else>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-bold">{{ dataModel.title }}</span>
|
||||
<n-icon style="font-size: 26px">
|
||||
<div v-if="dataModel.iconClass === 'HardwareChip'">
|
||||
<HardwareChip />
|
||||
</div>
|
||||
<div v-else-if="dataModel.iconClass === 'AppsSharp'">
|
||||
<AppsSharp />
|
||||
</div>
|
||||
<div v-else-if="dataModel.iconClass === 'Analytics'">
|
||||
<Analytics />
|
||||
</div>
|
||||
<div v-else-if="dataModel.iconClass === 'PieChart'">
|
||||
<PieChart />
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<Bookmark />
|
||||
</div>
|
||||
</n-icon>
|
||||
<div v-else>
|
||||
<Bookmark />
|
||||
</div>
|
||||
</n-icon>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<n-skeleton text v-if="loading" :repeat="6" />
|
||||
<template v-else>
|
||||
<div style="height: 130px" class="flex flex-col justify-between">
|
||||
<div class="flex flex-col justify-center">
|
||||
<span class="text-xxl">{{ dataModel.data }}</span>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center flex-1">
|
||||
<slot name="extra" :extra="dataModel.extra"></slot>
|
||||
</div>
|
||||
<div class="divide"></div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-grey">{{ dataModel.bottomTitle }}</span>
|
||||
<span class="text-sm text-grey">{{ dataModel.totalSum }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<n-skeleton text v-if="loading" :repeat="6" />
|
||||
<template v-else>
|
||||
<div style="height: 130px" class="flex flex-col justify-between">
|
||||
<div class="flex flex-col justify-center">
|
||||
<span class="text-xxl">{{ dataModel.data }}</span>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center flex-1">
|
||||
<slot name="extra" :extra="dataModel.extra"></slot>
|
||||
</div>
|
||||
<div class="divide"></div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-grey">{{ dataModel.bottomTitle }}</span>
|
||||
<span class="text-sm text-grey">{{ dataModel.totalSum }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</n-card>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@@ -1,88 +1,90 @@
|
||||
<template>
|
||||
<n-card
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '10px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<template #header>
|
||||
<n-skeleton text style="width: 50%" v-if="loading" />
|
||||
<template v-else>
|
||||
<div class="text-sm"> 实时网卡流量(全部网卡)</div>
|
||||
<div>
|
||||
<n-card
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '10px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<template #header>
|
||||
<n-skeleton text style="width: 50%" v-if="loading" />
|
||||
<template v-else>
|
||||
<div class="text-sm"> 实时网卡流量(全部网卡)</div>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<div class="chart-item-container">
|
||||
<n-skeleton text v-if="loading" :repeat="10" />
|
||||
<template v-else>
|
||||
<n-grid responsive="screen" cols="1 s:2 m:4 l:4 xl:4 2xl:4" x-gap="5" y-gap="5">
|
||||
<n-grid-item class="item-wrapper">
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<div class="text-number">{{ last.up }} KB</div>
|
||||
<div class="title-text">
|
||||
<n-badge :value="1" dot color="rgb(58, 104, 255)" />
|
||||
上行
|
||||
</div>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item class="item-wrapper">
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<div class="text-number"> {{ last.down ?? 0 }} KB</div>
|
||||
<div class="title-text">
|
||||
<n-badge :value="1" dot color="rgb(241, 136, 136)" />
|
||||
下行
|
||||
</div>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item class="item-wrapper">
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<div class="text-number">{{ last.bytesSent ?? 0 }}</div>
|
||||
<div class="title-text"> 总发送</div>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item class="item-wrapper">
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<div class="text-number">{{ last.bytesRecv ?? 0 }}</div>
|
||||
<div class="title-text"> 总接收</div>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<div ref="fullYearSalesChart" class="chart-item"></div>
|
||||
</template>
|
||||
</div>
|
||||
</n-card>
|
||||
<div class="chart-item-container">
|
||||
<n-skeleton text v-if="loading" :repeat="10" />
|
||||
<template v-else>
|
||||
<n-grid responsive="screen" cols="1 s:2 m:4 l:4 xl:4 2xl:4" x-gap="5" y-gap="5">
|
||||
<n-grid-item class="item-wrapper">
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<div class="text-number">{{ last?.up }} KB</div>
|
||||
<div class="title-text">
|
||||
<n-badge :value="1" dot color="rgb(58, 104, 255)" />
|
||||
上行
|
||||
</div>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item class="item-wrapper">
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<div class="text-number"> {{ last?.down ?? 0 }} KB</div>
|
||||
<div class="title-text">
|
||||
<n-badge :value="1" dot color="rgb(241, 136, 136)" />
|
||||
下行
|
||||
</div>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item class="item-wrapper">
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<div class="text-number">{{ last?.bytesSent ?? 0 }}</div>
|
||||
<div class="title-text"> 总发送</div>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item class="item-wrapper">
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:content-style="{ padding: '10px' }"
|
||||
:header-style="{ padding: '5px' }"
|
||||
:segmented="true"
|
||||
>
|
||||
<div class="text-number">{{ last?.bytesRecv ?? 0 }}</div>
|
||||
<div class="title-text"> 总接收</div>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<div ref="fullYearSalesChart" class="chart-item"></div>
|
||||
</template>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import useEcharts from '@/hooks/useEcharts';
|
||||
import { defineComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { defineComponent, nextTick, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import { dispose, graphic } from 'echarts';
|
||||
import { object } from 'vue-types';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FullYearSalesChart',
|
||||
props: {
|
||||
dataModel: {
|
||||
type: Array,
|
||||
type: Array || object,
|
||||
default: () => {
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
return {};
|
||||
},
|
||||
},
|
||||
@@ -94,7 +96,7 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const last = ref({
|
||||
const last = ref<any>({
|
||||
bytesSent: '0B',
|
||||
bytesRecv: '0B',
|
||||
down: '0',
|
||||
@@ -198,7 +200,6 @@
|
||||
const fullYearSalesChart = ref<HTMLDivElement | null>(null);
|
||||
watch(props, (_newVal, _oldVal) => {
|
||||
last.value = _newVal.dataModel[_newVal.dataModel.length - 1];
|
||||
// console.log('last _newVal:' + JSON.stringify(last.value));
|
||||
|
||||
if (months.value.length < 10) {
|
||||
for (let i = 0; i < _newVal.dataModel?.length; i++) {
|
||||
@@ -227,7 +228,9 @@
|
||||
useEcharts(fullYearSalesChart.value as HTMLDivElement).resize();
|
||||
};
|
||||
onBeforeUnmount(() => {
|
||||
dispose(fullYearSalesChart.value as HTMLDivElement);
|
||||
if (fullYearSalesChart.value !== null) {
|
||||
dispose(fullYearSalesChart.value as HTMLDivElement);
|
||||
}
|
||||
});
|
||||
return {
|
||||
fullYearSalesChart,
|
||||
|
@@ -1,84 +1,88 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<n-spin :show="loading" description="正在从服务器查询信息...">
|
||||
<n-grid responsive="screen" cols="1 s:2 m:4 l:4 xl:4 2xl:4" x-gap="5" y-gap="5">
|
||||
<n-grid-item v-for="(item, index) of dataSource.head" :key="index" class="item-wrapper">
|
||||
<DataItem :data-model="item" :loading="loading">
|
||||
<template v-if="index === 0" #extra="{ extra }">
|
||||
<div class="margin-top-lg">
|
||||
<div> {{ extra.data }}</div>
|
||||
<div class="margin-top-sm"> {{ extra.data1 }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="index === 1" #extra="{ extra }">
|
||||
<div class="margin-top" style="position: relative">
|
||||
<div> 已用内存:{{ extra.data }}</div>
|
||||
<div class="margin-top-sm"> 剩余内存:{{ extra.data1 }}</div>
|
||||
<div class="stack-avatar-wrapper"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="index === 2" #extra="{ extra }">
|
||||
<n-progress type="line" :percentage="extra.data" />
|
||||
</template>
|
||||
<template v-else-if="index === 3" #extra>
|
||||
<LoadChart ref="mLoadChart" :data-model="dataSource.load" />
|
||||
</template>
|
||||
</DataItem>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<div>
|
||||
<div class="main-container">
|
||||
<n-spin :show="loading" description="正在从服务器查询信息...">
|
||||
<n-grid responsive="screen" cols="1 s:2 m:4 l:4 xl:4 2xl:4" x-gap="5" y-gap="5">
|
||||
<n-grid-item v-for="(item, index) of dataSource.head" :key="index" class="item-wrapper">
|
||||
<DataItem :data-model="item" :loading="loading">
|
||||
<template v-if="index === 0" #extra="{ extra }">
|
||||
<div class="margin-top-lg">
|
||||
<div> {{ extra.data }}</div>
|
||||
<div class="margin-top-sm"> {{ extra.data1 }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="index === 1" #extra="{ extra }">
|
||||
<div class="margin-top" style="position: relative">
|
||||
<div> 已用内存:{{ extra.data }}</div>
|
||||
<div class="margin-top-sm"> 剩余内存:{{ extra.data1 }}</div>
|
||||
<div class="stack-avatar-wrapper"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="index === 2" #extra="{ extra }">
|
||||
<n-progress type="line" :percentage="extra.data" />
|
||||
</template>
|
||||
<template v-else-if="index === 3" #extra>
|
||||
<LoadChart ref="mLoadChart" :data-model="dataSource.load" />
|
||||
</template>
|
||||
</DataItem>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
|
||||
<n-grid class="mt-2">
|
||||
<n-grid-item :span="24">
|
||||
<FullYearSalesChart
|
||||
ref="fullYearSalesChart"
|
||||
:data-model="dataSource.net"
|
||||
:loading="loading"
|
||||
/>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<n-grid class="mt-2">
|
||||
<n-grid-item :span="24">
|
||||
<FullYearSalesChart
|
||||
ref="fullYearSalesChart"
|
||||
:data-model="dataSource.net"
|
||||
:loading="loading"
|
||||
/>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
|
||||
<n-space vertical style="padding-top: 10px">
|
||||
<n-card title="服务器信息">
|
||||
<n-descriptions
|
||||
label-placement="top"
|
||||
bordered
|
||||
cols="1 s:1 m:2 l:3 xl:4 2xl:4"
|
||||
:label-style="{ 'font-weight': 'bold', 'font-size': '16px' }"
|
||||
>
|
||||
<n-descriptions-item label="服务器名称">
|
||||
{{ dataRunInfo.hostname }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="操作系统"> {{ dataRunInfo.os }}</n-descriptions-item>
|
||||
<n-descriptions-item label="服务器IP">
|
||||
{{ dataRunInfo.intranet_ip }} /
|
||||
{{ dataRunInfo.public_ip }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="系统架构"> {{ dataRunInfo.arch }}</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-card>
|
||||
<n-card title="GO运行信息">
|
||||
<n-descriptions
|
||||
label-placement="top"
|
||||
bordered
|
||||
cols="1 s:1 m:2 l:3 xl:4 2xl:4"
|
||||
:label-style="{ 'font-weight': 'bold', 'font-size': '16px' }"
|
||||
>
|
||||
<n-descriptions-item label="语言环境"> {{ dataRunInfo.goName }}</n-descriptions-item>
|
||||
<n-descriptions-item label="版本号"> {{ dataRunInfo.version }}</n-descriptions-item>
|
||||
<n-descriptions-item label="启动时间"> {{ dataRunInfo.startTime }}</n-descriptions-item>
|
||||
<n-descriptions-item label="运行时长">
|
||||
{{ formatBefore(new Date(dataRunInfo.startTime)) }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="运行路径"> {{ dataRunInfo.pwd }}</n-descriptions-item>
|
||||
<n-descriptions-item label="goroutine数量">
|
||||
{{ dataRunInfo.goroutine }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="运行内存"> {{ dataRunInfo.goMem }}</n-descriptions-item>
|
||||
<n-descriptions-item label="磁盘占用"> {{ dataRunInfo.goSize }}</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-spin>
|
||||
<n-space vertical style="padding-top: 10px">
|
||||
<n-card title="服务器信息">
|
||||
<n-descriptions
|
||||
label-placement="top"
|
||||
bordered
|
||||
cols="1 s:1 m:2 l:3 xl:4 2xl:4"
|
||||
:label-style="{ 'font-weight': 'bold', 'font-size': '16px' }"
|
||||
>
|
||||
<n-descriptions-item label="服务器名称">
|
||||
{{ dataRunInfo.hostname }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="操作系统"> {{ dataRunInfo.os }}</n-descriptions-item>
|
||||
<n-descriptions-item label="服务器IP">
|
||||
{{ dataRunInfo.intranet_ip }} /
|
||||
{{ dataRunInfo.public_ip }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="系统架构"> {{ dataRunInfo.arch }}</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-card>
|
||||
<n-card title="GO运行信息">
|
||||
<n-descriptions
|
||||
label-placement="top"
|
||||
bordered
|
||||
cols="1 s:1 m:2 l:3 xl:4 2xl:4"
|
||||
:label-style="{ 'font-weight': 'bold', 'font-size': '16px' }"
|
||||
>
|
||||
<n-descriptions-item label="语言环境"> {{ dataRunInfo.goName }}</n-descriptions-item>
|
||||
<n-descriptions-item label="版本号"> {{ dataRunInfo.version }}</n-descriptions-item>
|
||||
<n-descriptions-item label="启动时间">
|
||||
{{ dataRunInfo.startTime }}</n-descriptions-item
|
||||
>
|
||||
<n-descriptions-item label="运行时长">
|
||||
{{ formatBefore(new Date(dataRunInfo.startTime)) }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="运行路径"> {{ dataRunInfo.pwd }}</n-descriptions-item>
|
||||
<n-descriptions-item label="goroutine数量">
|
||||
{{ dataRunInfo.goroutine }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="运行内存"> {{ dataRunInfo.goMem }}</n-descriptions-item>
|
||||
<n-descriptions-item label="磁盘占用"> {{ dataRunInfo.goSize }}</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-spin>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -90,7 +94,7 @@
|
||||
import { SocketEnum } from '@/enums/socketEnum';
|
||||
import { addOnMessage, sendMsg } from '@/utils/websocket';
|
||||
import { formatBefore } from '@/utils/dateUtil';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Home',
|
||||
@@ -164,34 +168,18 @@
|
||||
load: {},
|
||||
net: {},
|
||||
});
|
||||
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
const loading = ref(true);
|
||||
const onMessageList = inject('onMessageList');
|
||||
// const onAdminMonitorTrends = (res) => {
|
||||
//
|
||||
// const data = JSON.parse(res.data);
|
||||
// console.log('onAdminMonitorTrends...,'+ data.event)
|
||||
// if (data.event !== SocketEnum.EventAdminMonitorTrends) {
|
||||
// return;
|
||||
// }
|
||||
// console.log('onAdminMonitorTrends okokoko:,' + JSON.stringify(data))
|
||||
// loading.value = false;
|
||||
// if (data.code == SocketEnum.CodeErr) {
|
||||
// message.success('查询出错');
|
||||
// return;
|
||||
// }
|
||||
// dataSource.value = data.data;
|
||||
// console.log('dataSource.value.net:'+JSON.stringify(dataSource.value.net))
|
||||
// };
|
||||
//
|
||||
// addOnMessage(onMessageList, onAdminMonitorTrends);
|
||||
|
||||
const onAdminMonitor= (res) => {
|
||||
const onAdminMonitor = (res) => {
|
||||
const data = JSON.parse(res.data);
|
||||
if (data.event === SocketEnum.EventAdminMonitorRunInfo) {
|
||||
loading.value = false;
|
||||
if (data.code == SocketEnum.CodeErr) {
|
||||
message.success('查询出错');
|
||||
message.error('查询出错:' + data.event);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -202,19 +190,29 @@
|
||||
if (data.event === SocketEnum.EventAdminMonitorTrends) {
|
||||
loading.value = false;
|
||||
if (data.code == SocketEnum.CodeErr) {
|
||||
message.success('查询出错');
|
||||
message.error('查询出错:' + data.event);
|
||||
return;
|
||||
}
|
||||
dataSource.value = data.data;
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
addOnMessage(onMessageList, onAdminMonitor);
|
||||
|
||||
onMounted(() => {
|
||||
getInfo();
|
||||
|
||||
setTimeout(() => {
|
||||
if (loading.value) {
|
||||
loading.value = false;
|
||||
dialog.error({
|
||||
title: '错误',
|
||||
content: '连接超时,请刷新重试。如仍未解决请检查websocket连接是否正确!',
|
||||
positiveText: '确定',
|
||||
});
|
||||
}
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
onUpdated(() => {
|
||||
@@ -244,7 +242,6 @@
|
||||
const onResize = () => {
|
||||
setTimeout(() => {
|
||||
mLoadChart.value?.updateChart();
|
||||
// fullYearSalesChart.value?.updateChart();
|
||||
}, 500);
|
||||
};
|
||||
const collapse = true;
|
||||
|
@@ -87,7 +87,7 @@
|
||||
<FormOutlined />
|
||||
</n-icon>
|
||||
<span>编辑菜单{{ treeItemTitle ? `:${treeItemTitle}` : '' }}</span>
|
||||
<span style="font-size: 14px">{{ treeItemTitle }}</span>
|
||||
<!-- <span style="font-size: 14px">{{ treeItemTitle }}</span>-->
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
|
@@ -1,89 +1,90 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="网站名称" path="basicName">
|
||||
<n-input v-model:value="formValue.basicName" placeholder="请输入网站名称" />
|
||||
</n-form-item>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="网站名称" path="basicName">
|
||||
<n-input v-model:value="formValue.basicName" placeholder="请输入网站名称" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="网站logo" path="basicLogo">
|
||||
<BasicUpload
|
||||
:action="`${uploadUrl}/admin/upload/image`"
|
||||
:headers="uploadHeaders"
|
||||
:data="{ type: 0 }"
|
||||
name="file"
|
||||
:width="100"
|
||||
:height="100"
|
||||
:maxNumber="1"
|
||||
@uploadChange="uploadChange"
|
||||
v-model:value="formValue.basicLogo"
|
||||
:helpText="
|
||||
'网站logo适用于客户端使用,图片大小不超过' +
|
||||
componentSetting.upload.maxSize +
|
||||
'MB'
|
||||
"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="网站logo" path="basicLogo">
|
||||
<BasicUpload
|
||||
:action="`${uploadUrl}/admin/upload/image`"
|
||||
:headers="uploadHeaders"
|
||||
:data="{ type: 0 }"
|
||||
name="file"
|
||||
:width="100"
|
||||
:height="100"
|
||||
:maxNumber="1"
|
||||
@uploadChange="uploadChange"
|
||||
v-model:value="formValue.basicLogo"
|
||||
:helpText="
|
||||
'网站logo适用于客户端使用,图片大小不超过' + componentSetting.upload.maxSize + 'MB'
|
||||
"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="网站域名" path="basicDomain">
|
||||
<n-input v-model:value="formValue.basicDomain" placeholder="请输入网站域名" />
|
||||
</n-form-item>
|
||||
<n-form-item label="网站域名" path="basicDomain">
|
||||
<n-input v-model:value="formValue.basicDomain" placeholder="请输入网站域名" />
|
||||
<template #feedback>
|
||||
如果客户端通过IP访问,则认为是调试模式,走实际请求地址,否则走该配置
|
||||
</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="用户是否可注册开关" path="basicRegisterSwitch">
|
||||
<n-radio-group
|
||||
v-model:value="formValue.basicRegisterSwitch"
|
||||
name="basicRegisterSwitch"
|
||||
>
|
||||
<n-space>
|
||||
<n-radio :value="1">开启</n-radio>
|
||||
<n-radio :value="0">关闭</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
<n-form-item label="websocket地址" path="basicWsAddr">
|
||||
<n-input v-model:value="formValue.basicWsAddr" placeholder="请输入websocket地址" />
|
||||
<template #feedback>
|
||||
如果客户端通过IP访问,则认为是调试模式,走实际请求地址,否则走该配置
|
||||
</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="验证码开关" path="basicCaptchaSwitch">
|
||||
<n-radio-group v-model:value="formValue.basicCaptchaSwitch" name="basicCaptchaSwitch">
|
||||
<n-space>
|
||||
<n-radio :value="1">开启</n-radio>
|
||||
<n-radio :value="0">关闭</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
<n-form-item label="用户是否可注册开关" path="basicRegisterSwitch">
|
||||
<n-radio-group v-model:value="formValue.basicRegisterSwitch" name="basicRegisterSwitch">
|
||||
<n-space>
|
||||
<n-radio :value="1">开启</n-radio>
|
||||
<n-radio :value="0">关闭</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="网站开启访问" path="basicSystemOpen">
|
||||
<n-switch
|
||||
size="large"
|
||||
v-model:value="formValue.basicSystemOpen"
|
||||
@update:value="systemOpenChange"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="验证码开关" path="basicCaptchaSwitch">
|
||||
<n-radio-group v-model:value="formValue.basicCaptchaSwitch" name="basicCaptchaSwitch">
|
||||
<n-space>
|
||||
<n-radio :value="1">开启</n-radio>
|
||||
<n-radio :value="0">关闭</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="网站关闭提示" path="basicCloseText">
|
||||
<n-input
|
||||
v-model:value="formValue.basicCloseText"
|
||||
type="textarea"
|
||||
placeholder="请输入网站关闭提示"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="网站开启访问" path="basicSystemOpen">
|
||||
<n-switch
|
||||
size="large"
|
||||
v-model:value="formValue.basicSystemOpen"
|
||||
@update:value="systemOpenChange"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="备案编号" path="basicIcpCode">
|
||||
<n-input placeholder="请输入备案编号" v-model:value="formValue.basicIcpCode" />
|
||||
</n-form-item>
|
||||
<n-form-item label="网站关闭提示" path="basicCloseText">
|
||||
<n-input
|
||||
v-model:value="formValue.basicCloseText"
|
||||
type="textarea"
|
||||
placeholder="请输入网站关闭提示"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="版权所有" path="basicCopyright">
|
||||
<n-input placeholder="版权所有" v-model:value="formValue.basicCopyright" />
|
||||
</n-form-item>
|
||||
<n-form-item label="备案编号" path="basicIcpCode">
|
||||
<n-input placeholder="请输入备案编号" v-model:value="formValue.basicIcpCode" />
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<n-form-item label="版权所有" path="basicCopyright">
|
||||
<n-input placeholder="版权所有" v-model:value="formValue.basicCopyright" />
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
@@ -127,6 +128,7 @@
|
||||
basicName: 'HotGo',
|
||||
basicLogo: '',
|
||||
basicDomain: 'https://hotgo.facms.cn',
|
||||
basicWsAddr: 'wss://hotgo.facms.cn/socket',
|
||||
basicIcpCode: '',
|
||||
basicLoginCode: 0,
|
||||
basicRegisterSwitch: 1,
|
||||
|
@@ -1,95 +1,87 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="SMTP服务器" path="smtpHost">
|
||||
<n-input v-model:value="formValue.smtpHost" placeholder="" />
|
||||
<template #feedback> 错误的配置发送邮件会导致服务器超时</template>
|
||||
</n-form-item>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="SMTP服务器" path="smtpHost">
|
||||
<n-input v-model:value="formValue.smtpHost" placeholder="" />
|
||||
<template #feedback> 错误的配置发送邮件会导致服务器超时</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="SMTP端口" path="smtpPort">
|
||||
<n-input-number
|
||||
v-model:value="formValue.smtpPort"
|
||||
placeholder=""
|
||||
:show-button="false"
|
||||
/>
|
||||
<template #feedback> (不加密默认25,SSL默认465,TLS默认587)</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="SMTP用户名" path="smtpUser">
|
||||
<n-input v-model:value="formValue.smtpUser" placeholder="" />
|
||||
<template #feedback>填写完整用户名</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="SMTP端口" path="smtpPort">
|
||||
<n-input-number v-model:value="formValue.smtpPort" placeholder="" :show-button="false" />
|
||||
<template #feedback> (不加密默认25,SSL默认465,TLS默认587)</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="SMTP用户名" path="smtpUser">
|
||||
<n-input v-model:value="formValue.smtpUser" placeholder="" />
|
||||
<template #feedback>填写完整用户名</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="SMTP密码" path="smtpPass">
|
||||
<n-input
|
||||
v-model:value="formValue.smtpPass"
|
||||
placeholder=""
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
<template #feedback>填写您的密码</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="SMTP密码" path="smtpPass">
|
||||
<n-input
|
||||
v-model:value="formValue.smtpPass"
|
||||
placeholder=""
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
<template #feedback>填写您的密码</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="发件人名称" path="smtpSendName">
|
||||
<n-input v-model:value="formValue.smtpSendName" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-form-item label="发件人名称" path="smtpSendName">
|
||||
<n-input v-model:value="formValue.smtpSendName" placeholder="" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="管理员邮箱" path="smtpAdminMailbox">
|
||||
<n-input v-model:value="formValue.smtpAdminMailbox" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-form-item label="管理员邮箱" path="smtpAdminMailbox">
|
||||
<n-input v-model:value="formValue.smtpAdminMailbox" placeholder="" />
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">发信限制</n-divider>
|
||||
<n-form-item label="最小发送间隔" path="smtpMinInterval">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smtpMinInterval"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
<template #feedback> 同地址</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="IP最大发送次数" path="smtpMaxIpLimit">
|
||||
<n-input-number v-model:value="formValue.smtpMaxIpLimit" placeholder="" />
|
||||
<template #feedback> 同IP每天最大允许发送次数 </template>
|
||||
</n-form-item>
|
||||
<n-form-item label="验证码有效期" path="smtpCodeExpire">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smtpCodeExpire"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-divider title-placement="left">发信限制</n-divider>
|
||||
<n-form-item label="最小发送间隔" path="smtpMinInterval">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smtpMinInterval"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
<template #feedback> 同地址</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="IP最大发送次数" path="smtpMaxIpLimit">
|
||||
<n-input-number v-model:value="formValue.smtpMaxIpLimit" placeholder="" />
|
||||
<template #feedback> 同IP每天最大允许发送次数 </template>
|
||||
</n-form-item>
|
||||
<n-form-item label="验证码有效期" path="smtpCodeExpire">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smtpCodeExpire"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="邮件模板" path="smtpTemplate">
|
||||
<n-dynamic-input
|
||||
v-model:value="formValue.smtpTemplate"
|
||||
preset="pair"
|
||||
key-placeholder="事件KEY"
|
||||
value-placeholder="模板路径"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="邮件模板" path="smtpTemplate">
|
||||
<n-dynamic-input
|
||||
v-model:value="formValue.smtpTemplate"
|
||||
preset="pair"
|
||||
key-placeholder="事件KEY"
|
||||
value-placeholder="模板路径"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
<n-button type="default" @click="sendTest">发送测试邮件</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
<n-button type="default" @click="sendTest">发送测试邮件</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
|
||||
<n-modal
|
||||
|
@@ -1,34 +1,30 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="高德Web服务key" path="geoAmapWebKey">
|
||||
<n-input
|
||||
v-model:value="formValue.geoAmapWebKey"
|
||||
placeholder=""
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
<template #feedback> 申请地址:https://console.amap.com/dev/key/app</template>
|
||||
</n-form-item>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="高德Web服务key" path="geoAmapWebKey">
|
||||
<n-input
|
||||
v-model:value="formValue.geoAmapWebKey"
|
||||
placeholder=""
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
<template #feedback> 申请地址:https://console.amap.com/dev/key/app</template>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,90 +1,86 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="默认驱动" path="smsDrive">
|
||||
<n-select
|
||||
placeholder="默认发送驱动"
|
||||
:options="options.config_sms_drive"
|
||||
v-model:value="formValue.smsDrive"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="默认驱动" path="smsDrive">
|
||||
<n-select
|
||||
placeholder="默认发送驱动"
|
||||
:options="options.config_sms_drive"
|
||||
v-model:value="formValue.smsDrive"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">发信限制</n-divider>
|
||||
<n-form-item label="最小发送间隔" path="smsMinInterval">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smsMinInterval"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
<template #feedback> 同号码</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="IP最大发送次数" path="smsMaxIpLimit">
|
||||
<n-input-number v-model:value="formValue.smsMaxIpLimit" placeholder="" />
|
||||
<template #feedback> 同IP每天最大允许发送次数 </template>
|
||||
</n-form-item>
|
||||
<n-form-item label="验证码有效期" path="smsCodeExpire">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smsCodeExpire"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-divider title-placement="left">发信限制</n-divider>
|
||||
<n-form-item label="最小发送间隔" path="smsMinInterval">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smsMinInterval"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
<template #feedback> 同号码</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="IP最大发送次数" path="smsMaxIpLimit">
|
||||
<n-input-number v-model:value="formValue.smsMaxIpLimit" placeholder="" />
|
||||
<template #feedback> 同IP每天最大允许发送次数 </template>
|
||||
</n-form-item>
|
||||
<n-form-item label="验证码有效期" path="smsCodeExpire">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smsCodeExpire"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">阿里云</n-divider>
|
||||
<n-form-item label="AccessKeyID" path="smsAliyunAccessKeyID">
|
||||
<n-input v-model:value="formValue.smsAliyunAccessKeyID" placeholder="" />
|
||||
<template #feedback
|
||||
>应用key和密钥你可以通过 https://ram.console.aliyun.com/manage/ak 获取</template
|
||||
>
|
||||
</n-form-item>
|
||||
<n-divider title-placement="left">阿里云</n-divider>
|
||||
<n-form-item label="AccessKeyID" path="smsAliyunAccessKeyID">
|
||||
<n-input v-model:value="formValue.smsAliyunAccessKeyID" placeholder="" />
|
||||
<template #feedback
|
||||
>应用key和密钥你可以通过 https://ram.console.aliyun.com/manage/ak 获取</template
|
||||
>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="AccessKeySecret" path="smsAliyunAccessKeySecret">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.smsAliyunAccessKeySecret"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
<n-form-item label="AccessKeySecret" path="smsAliyunAccessKeySecret">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.smsAliyunAccessKeySecret"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="签名" path="smsAliyunSign">
|
||||
<n-input v-model:value="formValue.smsAliyunSign" placeholder="" />
|
||||
<template #feedback
|
||||
>申请地址:https://dysms.console.aliyun.com/domestic/text/sign</template
|
||||
>
|
||||
</n-form-item>
|
||||
<n-form-item label="签名" path="smsAliyunSign">
|
||||
<n-input v-model:value="formValue.smsAliyunSign" placeholder="" />
|
||||
<template #feedback
|
||||
>申请地址:https://dysms.console.aliyun.com/domestic/text/sign</template
|
||||
>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="短信模板" path="smsAliyunTemplate">
|
||||
<n-dynamic-input
|
||||
v-model:value="formValue.smsAliyunTemplate"
|
||||
preset="pair"
|
||||
key-placeholder="事件KEY"
|
||||
value-placeholder="模板CODE"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="短信模板" path="smsAliyunTemplate">
|
||||
<n-dynamic-input
|
||||
v-model:value="formValue.smsAliyunTemplate"
|
||||
preset="pair"
|
||||
key-placeholder="事件KEY"
|
||||
value-placeholder="模板CODE"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
<n-button type="default" @click="sendTest">发送测试短信</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
<n-button type="default" @click="sendTest">发送测试短信</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
|
||||
<n-modal
|
||||
|
@@ -1,31 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="默认主题" path="themeDarkTheme">
|
||||
<n-input v-model:value="formValue.themeDarkTheme" placeholder="" />
|
||||
<template #feedback> 可选:'dark' 、 'light' </template>
|
||||
</n-form-item>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="默认主题" path="themeDarkTheme">
|
||||
<n-input v-model:value="formValue.themeDarkTheme" placeholder="" />
|
||||
<template #feedback> 可选:'dark' 、 'light' </template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="默认系统主题" path="themeAppTheme">
|
||||
<n-input v-model:value="formValue.themeAppTheme" placeholder="" />
|
||||
<template #feedback> 默认:#2d8cf0 </template>
|
||||
</n-form-item>
|
||||
<n-form-item label="默认侧边栏风格" path="themeNavTheme">
|
||||
<n-input v-model:value="formValue.themeNavTheme" placeholder="" />
|
||||
<template #feedback>可选:'light'、 'header-dark'</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="默认系统主题" path="themeAppTheme">
|
||||
<n-input v-model:value="formValue.themeAppTheme" placeholder="" />
|
||||
<template #feedback> 默认:#2d8cf0 </template>
|
||||
</n-form-item>
|
||||
<n-form-item label="默认侧边栏风格" path="themeNavTheme">
|
||||
<n-input v-model:value="formValue.themeNavTheme" placeholder="" />
|
||||
<template #feedback>可选:'light'、 'header-dark'</template>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,108 +1,104 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="默认驱动" path="uploadDrive">
|
||||
<n-select
|
||||
placeholder="默认驱动"
|
||||
:options="uploadDriveList"
|
||||
v-model:value="formValue.uploadDrive"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="默认驱动" path="uploadDrive">
|
||||
<n-select
|
||||
placeholder="默认驱动"
|
||||
:options="uploadDriveList"
|
||||
v-model:value="formValue.uploadDrive"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">上传限制</n-divider>
|
||||
<n-form-item label="图片大小限制" path="uploadImageSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadImageSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-form-item label="图片类型限制" path="uploadImageType">
|
||||
<n-input v-model:value="formValue.uploadImageType" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-divider title-placement="left">上传限制</n-divider>
|
||||
<n-form-item label="图片大小限制" path="uploadImageSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadImageSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-form-item label="图片类型限制" path="uploadImageType">
|
||||
<n-input v-model:value="formValue.uploadImageType" placeholder="" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="文件大小限制" path="uploadFileSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadFileSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-form-item label="文件类型限制" path="uploadFileType">
|
||||
<n-input v-model:value="formValue.uploadFileType" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-form-item label="文件大小限制" path="uploadFileSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadFileSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-form-item label="文件类型限制" path="uploadFileType">
|
||||
<n-input v-model:value="formValue.uploadFileType" placeholder="" />
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">本地存储</n-divider>
|
||||
<n-form-item label="本地存储路径" path="uploadLocalPath">
|
||||
<n-input v-model:value="formValue.uploadLocalPath" placeholder="" />
|
||||
<template #feedback>填对外访问的相对路径</template>
|
||||
</n-form-item>
|
||||
<n-divider title-placement="left">本地存储</n-divider>
|
||||
<n-form-item label="本地存储路径" path="uploadLocalPath">
|
||||
<n-input v-model:value="formValue.uploadLocalPath" placeholder="" />
|
||||
<template #feedback>填对外访问的相对路径</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">UCloud存储</n-divider>
|
||||
<n-form-item label="公钥" path="uploadUCloudPublicKey">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.uploadUCloudPublicKey"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
<template #feedback>获取地址:https://console.ucloud.cn/ufile/token</template>
|
||||
</n-form-item>
|
||||
<n-divider title-placement="left">UCloud存储</n-divider>
|
||||
<n-form-item label="公钥" path="uploadUCloudPublicKey">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.uploadUCloudPublicKey"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
<template #feedback>获取地址:https://console.ucloud.cn/ufile/token</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="私钥" path="uploadUCloudPrivateKey">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.uploadUCloudPrivateKey"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
<n-form-item label="存储路径" path="uploadUCloudPath">
|
||||
<n-input v-model:value="formValue.uploadUCloudPath" placeholder="" />
|
||||
<template #feedback>填对对象存储中的相对路径</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="地域API" path="uploadUCloudBucketHost">
|
||||
<n-input v-model:value="formValue.uploadUCloudBucketHost" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-form-item label="存储桶名称" path="uploadUCloudBucketName">
|
||||
<n-input v-model:value="formValue.uploadUCloudBucketName" placeholder="" />
|
||||
<template #feedback>存储空间名称</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="存储桶地域host" path="uploadUCloudFileHost">
|
||||
<n-input v-model:value="formValue.uploadUCloudFileHost" placeholder="" />
|
||||
<template #feedback>不需要包含桶名称</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="访问域名" path="uploadUCloudEndpoint">
|
||||
<n-input v-model:value="formValue.uploadUCloudEndpoint" placeholder="" />
|
||||
<template #feedback>格式,http://abc.com 或 https://abc.com,不可为空</template>
|
||||
</n-form-item>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
<n-form-item label="私钥" path="uploadUCloudPrivateKey">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.uploadUCloudPrivateKey"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #password-visible-icon>
|
||||
<n-icon :size="16" :component="GlassesOutline" />
|
||||
</template>
|
||||
<template #password-invisible-icon>
|
||||
<n-icon :size="16" :component="Glasses" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
<n-form-item label="存储路径" path="uploadUCloudPath">
|
||||
<n-input v-model:value="formValue.uploadUCloudPath" placeholder="" />
|
||||
<template #feedback>填对对象存储中的相对路径</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="地域API" path="uploadUCloudBucketHost">
|
||||
<n-input v-model:value="formValue.uploadUCloudBucketHost" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-form-item label="存储桶名称" path="uploadUCloudBucketName">
|
||||
<n-input v-model:value="formValue.uploadUCloudBucketName" placeholder="" />
|
||||
<template #feedback>存储空间名称</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="存储桶地域host" path="uploadUCloudFileHost">
|
||||
<n-input v-model:value="formValue.uploadUCloudFileHost" placeholder="" />
|
||||
<template #feedback>不需要包含桶名称</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="访问域名" path="uploadUCloudEndpoint">
|
||||
<n-input v-model:value="formValue.uploadUCloudEndpoint" placeholder="" />
|
||||
<template #feedback>格式,http://abc.com 或 https://abc.com,不可为空</template>
|
||||
</n-form-item>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-grid :x-gap="24">
|
||||
<n-grid cols="24 300:1 600:24" :x-gap="24">
|
||||
<n-grid-item span="6">
|
||||
<n-card :bordered="false" size="small" class="proCard">
|
||||
<n-thing
|
||||
|
16363
web/yarn.lock
16363
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user