pull/213/head
xiaojunnuo 2024-10-03 01:29:12 +08:00
parent aeed24e87d
commit c9d18f6d8a
17 changed files with 100 additions and 34 deletions

View File

@ -16,6 +16,11 @@ export class HttpError extends Error {
return; return;
} }
super(error.message); super(error.message);
if (error?.message?.indexOf("ssl3_get_record:wrong version number") > -1) {
this.message = "http协议错误服务端要求http协议请检查是否使用了https请求";
}
this.name = error.name; this.name = error.name;
this.code = error.code; this.code = error.code;
this.cause = error.cause; this.cause = error.cause;

View File

@ -1,7 +1,7 @@
import axios from "axios"; import axios from "axios";
import { get } from "lodash-es"; import { get } from "lodash-es";
import Adapter from "axios-mock-adapter"; import Adapter from "axios-mock-adapter";
import { errorLog, errorCreate } from "./tools"; import { errorLog, errorCreate, response } from "./tools";
import { env } from "/src/utils/util.env"; import { env } from "/src/utils/util.env";
import { useUserStore } from "../store/modules/user"; import { useUserStore } from "../store/modules/user";
/** /**
@ -96,6 +96,10 @@ function createService() {
const userStore = useUserStore(); const userStore = useUserStore();
userStore.logout(); userStore.logout();
} }
if (error?.config?.onError) {
error.config.onError(error);
}
return Promise.reject(error); return Promise.reject(error);
} }
); );

View File

@ -55,6 +55,9 @@ export function errorLog(error: any) {
if (error.response?.data?.message) { if (error.response?.data?.message) {
message = error.response.data.message; message = error.response.data.message;
} }
if (message.indexOf("ssl3_get_record:wrong version number" > -1)) {
message = "http协议错误服务端要求http协议请检查是否使用了https请求";
}
// 显示提示 // 显示提示
uiContext.get().notification.error({ message }); uiContext.get().notification.error({ message });
} }

View File

@ -13,13 +13,21 @@ const emit = defineEmits<{
}>(); }>();
const optionsRef = ref([]); const optionsRef = ref([]);
const message = ref("");
const getOptions = async () => { const getOptions = async () => {
return await doRequest({ return await doRequest(
{
type: props.type, type: props.type,
typeName: props.typeName, typeName: props.typeName,
action: props.action, action: props.action,
input: props.form input: props.form
}); },
{
onError(err) {
message.value = err.message;
}
}
);
}; };
const filterOption = (input: string, option: any) => { const filterOption = (input: string, option: any) => {
@ -53,6 +61,7 @@ watch(
</script> </script>
<template> <template>
<div>
<a-select <a-select
class="remote-select" class="remote-select"
show-search show-search
@ -62,6 +71,10 @@ watch(
@click="onClick" @click="onClick"
@update:value="emit('update:value', $event)" @update:value="emit('update:value', $event)"
/> />
<div class="helper">
{{ message }}
</div>
</div>
</template> </template>
<style lang="less"></style> <style lang="less"></style>

View File

@ -14,7 +14,7 @@ export type RequestHandleReq<T = any> = {
input: T; input: T;
}; };
export async function doRequest(req: RequestHandleReq) { export async function doRequest(req: RequestHandleReq, opts?: any = {}) {
const url = req.type === "access" ? "/pi/handle/access" : "/pi/handle/plugin"; const url = req.type === "access" ? "/pi/handle/access" : "/pi/handle/plugin";
const { typeName, action, data, input } = req; const { typeName, action, data, input } = req;
const res = await request({ const res = await request({
@ -25,7 +25,8 @@ export async function doRequest(req: RequestHandleReq) {
action, action,
data, data,
input input
} },
...opts
}); });
return res; return res;
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<contextHolder /> <contextHolder />
<a-input :value="value" :allow-clear="true" @update:value="emit('update:value', $event)"> <a-input v-bind="attrs" :value="value" :allow-clear="true" @update:value="emit('update:value', $event)">
<template #suffix> <template #suffix>
<a-tag class="cursor-pointer" @click="getDeviceId">ID</a-tag> <a-tag class="cursor-pointer" @click="getDeviceId">ID</a-tag>
</template> </template>

View File

@ -33,18 +33,19 @@ type Text = {
title?: string; title?: string;
}; };
const text = computed<Text>(() => { const text = computed<Text>(() => {
const vipLabel = userStore.vipLabel;
const map = { const map = {
isPlus: { isPlus: {
button: { button: {
name: "专业版已开通", name: `${vipLabel}已开通`,
title: "到期时间:" + expireTime.value title: "到期时间:" + expireTime.value
}, },
icon: { icon: {
name: "", name: "",
title: "专业版已开通" title: `${vipLabel}已开通`
}, },
nav: { nav: {
name: "专业版", name: `${vipLabel}`,
title: "到期时间:" + expireTime.value title: "到期时间:" + expireTime.value
} }
}, },
@ -82,7 +83,7 @@ const expiredDays = computed(() => {
if (userStore.plusInfo?.isPlus && !userStore.isPlus) { if (userStore.plusInfo?.isPlus && !userStore.isPlus) {
// //
const days = dayjs().diff(dayjs(userStore.plusInfo.expireTime), "day"); const days = dayjs().diff(dayjs(userStore.plusInfo.expireTime), "day");
return `专业版已过期${days}`; return `${userStore.vipLabel}已过期${days}`;
} }
return ""; return "";
}); });
@ -100,15 +101,16 @@ async function doActive() {
const res = await api.doActive(formState); const res = await api.doActive(formState);
if (res) { if (res) {
await userStore.reInit(); await userStore.reInit();
const vipLabel = userStore.vipLabel;
Modal.success({ Modal.success({
title: "激活成功", title: "激活成功",
content: `您已成功激活专业版,有效期至:${dayjs(userStore.plusInfo.expireTime).format("YYYY-MM-DD")}`, content: `您已成功激活${vipLabel},有效期至:${dayjs(userStore.plusInfo.expireTime).format("YYYY-MM-DD")}`,
onOk() { onOk() {
if (!(settingStore.installInfo.bindUserId > 0)) { if (!(settingStore.installInfo.bindUserId > 0)) {
// //
Modal.confirm({ Modal.confirm({
title: "是否绑定袖手账号", title: "是否绑定袖手账号",
content: "绑定账号后,可以避免专业版License丢失强烈建议绑定", content: "绑定账号后,可以避免License丢失强烈建议绑定",
onOk() { onOk() {
router.push("/sys/account"); router.push("/sys/account");
} }
@ -130,8 +132,15 @@ function openUpgrade() {
} }
const placeholder = "请输入激活码"; const placeholder = "请输入激活码";
const isPlus = userStore.isPlus; const isPlus = userStore.isPlus;
let title = "激活专业版/商业版";
if (userStore.isComm) {
title = "续期商业版";
} else if (userStore.isPlus) {
title = "续期专业版/升级商业版";
}
modal.confirm({ modal.confirm({
title: isPlus ? "续期专业版" : "激活专业版", title,
async onOk() { async onOk() {
return await doActive(); return await doActive();
}, },
@ -139,6 +148,7 @@ function openUpgrade() {
okText: "激活", okText: "激活",
width: 500, width: 500,
content: () => { content: () => {
const vipLabel = userStore.vipLabel;
return ( return (
<div class="mt-10 mb-10"> <div class="mt-10 mb-10">
<div> <div>
@ -153,7 +163,7 @@ function openUpgrade() {
</div> </div>
<div> <div>
<h3 class="block-header">{isPlus ? "续期" : "立刻激活"}</h3> <h3 class="block-header">{isPlus ? "续期" : "立刻激活"}</h3>
<div>{isPlus ? "当前专业版已激活,到期时间" + dayjs(userStore.plusInfo.expireTime).format("YYYY-MM-DD") : ""}</div> <div>{isPlus ? `当前${vipLabel}已激活,到期时间` + dayjs(userStore.plusInfo.expireTime).format("YYYY-MM-DD") : ""}</div>
<div class="mt-10"> <div class="mt-10">
<div class="flex-o w-100"> <div class="flex-o w-100">
<span>站点ID</span> <span>站点ID</span>

View File

@ -350,7 +350,7 @@ function install(app: App, options: any = {}) {
} }
columnProps.column.resizable = true; columnProps.column.resizable = true;
if (!columnProps.column.width) { if (!columnProps.column.width) {
columnProps.column.width = 100; columnProps.column.width = -1;
} else if (typeof columnProps.column?.width === "string" && columnProps.column.width.indexOf("px") > -1) { } else if (typeof columnProps.column?.width === "string" && columnProps.column.width.indexOf("px") > -1) {
columnProps.column.width = parseInt(columnProps.column.width.replace("px", "")); columnProps.column.width = parseInt(columnProps.column.width.replace("px", ""));
} }

View File

@ -23,6 +23,7 @@ interface PlusInfo {
vipType: string; vipType: string;
expireTime: number; expireTime: number;
isPlus: boolean; isPlus: boolean;
isComm: boolean;
} }
const USER_INFO_KEY = "USER_INFO"; const USER_INFO_KEY = "USER_INFO";
@ -46,10 +47,21 @@ export const useUserStore = defineStore({
return this.token || LocalStorage.get(TOKEN_KEY); return this.token || LocalStorage.get(TOKEN_KEY);
}, },
isAdmin(): boolean { isAdmin(): boolean {
return this.getUserInfo?.id === 1; return this.getUserInfo.id === 1 || this.getUserInfo.roles?.includes(1);
}, },
isPlus(): boolean { isPlus(): boolean {
return this.plusInfo?.isPlus && this.plusInfo?.expireTime > new Date().getTime(); return this.plusInfo?.isPlus && this.plusInfo?.expireTime > new Date().getTime();
},
isComm(): boolean {
return this.plusInfo?.isComm && this.plusInfo?.expireTime > new Date().getTime();
},
vipLabel(): string {
const vipLabelMap: any = {
free: "免费版",
vip: "专业版",
comm: "商业版"
};
return vipLabelMap[this.plusInfo?.vipType];
} }
}, },
actions: { actions: {

View File

@ -40,7 +40,7 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
type: "text", type: "text",
form: { show: false }, // 表单配置 form: { show: false }, // 表单配置
column: { column: {
width: 70, width: 100,
sorter: true sorter: true
} }
}, },
@ -74,7 +74,8 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
}, },
editForm: { component: { disabled: true } }, editForm: { component: { disabled: true } },
column: { column: {
sorter: true sorter: true,
width: 200
} }
}, },
password: { password: {

View File

@ -17,18 +17,21 @@
# password: root # password: root
# database: postgres # database: postgres
typeorm:
dataSource:
default:
database: './data/db-comm.sqlite'
#plus:
# server:
# baseUrls: ['https://api.ai.handsfree.work', 'https://api.ai.docmirror.cn']
plus: plus:
server: server:
baseUrls: ['https://api.ai.handsfree.work', 'https://api.ai.docmirror.cn'] baseUrls: ['http://127.0.0.1:11007']
#typeorm:
# dataSource:
# default:
# database: './data/db2.sqlite'
#account:
# server:
# baseUrl: 'http://127.0.0.1:1017/subject'
account: account:
server: server:
baseUrl: 'https://ai.handsfree.work/subject' baseUrl: 'http://127.0.0.1:1017/subject'
#account:
# server:
# baseUrl: 'https://ai.handsfree.work/subject'

View File

@ -24,6 +24,7 @@
"@alicloud/pop-core": "^1.7.10", "@alicloud/pop-core": "^1.7.10",
"@certd/acme-client": "^1.25.9", "@certd/acme-client": "^1.25.9",
"@certd/lib-huawei": "^1.25.9", "@certd/lib-huawei": "^1.25.9",
"@certd/commcial-core": "^1.25.9",
"@certd/lib-jdcloud": "^1.25.9", "@certd/lib-jdcloud": "^1.25.9",
"@certd/lib-k8s": "^1.25.9", "@certd/lib-k8s": "^1.25.9",
"@certd/midway-flyway-js": "^1.25.9", "@certd/midway-flyway-js": "^1.25.9",

View File

@ -49,6 +49,9 @@ export class RoleController extends CrudController<RoleService> {
@Query('id') @Query('id')
id: number id: number
) { ) {
if (id === 1) {
throw new Error('不能删除默认的管理员角色');
}
return await super.delete(id); return await super.delete(id);
} }

View File

@ -73,8 +73,11 @@ export class UserController extends CrudController<UserService> {
@Post('/delete', { summary: 'sys:auth:user:remove' }) @Post('/delete', { summary: 'sys:auth:user:remove' })
async delete( async delete(
@Query('id') @Query('id')
id : number id: number
) { ) {
if (id === 1) {
throw new Error('不能删除默认的管理员用户');
}
return await super.delete(id); return await super.delete(id);
} }

View File

@ -66,4 +66,6 @@ export class UserEntity {
static of(user: Partial<UserEntity>) { static of(user: Partial<UserEntity>) {
return Object.assign(new UserEntity(), user); return Object.assign(new UserEntity(), user);
} }
roleIds: number[];
} }

View File

@ -3,6 +3,7 @@ import { BaseController } from '../../../basic/base-controller.js';
import { Constants } from '../../../basic/constants.js'; import { Constants } from '../../../basic/constants.js';
import { UserService } from '../../authority/service/user-service.js'; import { UserService } from '../../authority/service/user-service.js';
import { getPlusInfo } from '@certd/pipeline'; import { getPlusInfo } from '@certd/pipeline';
import { RoleService } from '../../authority/service/role-service.js';
/** /**
*/ */
@ -11,10 +12,13 @@ import { getPlusInfo } from '@certd/pipeline';
export class MineController extends BaseController { export class MineController extends BaseController {
@Inject() @Inject()
userService: UserService; userService: UserService;
@Inject()
roleService: RoleService;
@Post('/info', { summary: Constants.per.authOnly }) @Post('/info', { summary: Constants.per.authOnly })
public async info() { public async info() {
const userId = this.getUserId(); const userId = this.getUserId();
const user = await this.userService.info(userId); const user = await this.userService.info(userId);
user.roleIds = await this.roleService.getRoleIdsByUserId(userId);
delete user.password; delete user.password;
return this.ok(user); return this.ok(user);
} }

View File

@ -27,4 +27,5 @@ export class UserSettingsEntity {
default: () => 'CURRENT_TIMESTAMP', default: () => 'CURRENT_TIMESTAMP',
}) })
updateTime: Date; updateTime: Date;
} }