Browse Source

feat: 0416会议功能点修改提交

master
AaronWu 1 year ago
parent
commit
dba26f8ace
  1. 2
      .env.development
  2. 2
      .env.production
  3. 2
      src/api/issue/model.d.ts
  4. 22
      src/api/user/index.ts
  5. 1
      src/api/user/model.d.ts
  6. 1
      src/assets/icons/audit.svg
  7. 6
      src/layout/header/index.vue
  8. 1
      src/locales/lang/en-US/layout.ts
  9. 1
      src/locales/lang/en-US/routes/account.ts
  10. 1
      src/locales/lang/zh-CN/layout.ts
  11. 1
      src/locales/lang/zh-CN/routes/account.ts
  12. 2
      src/plugins/antd.ts
  13. 9
      src/router/constant.ts
  14. 2
      src/router/index.ts
  15. 2
      src/router/router-guards.ts
  16. 1
      src/store/modules/user.ts
  17. 73
      src/views/client/entrance/index.vue
  18. 165
      src/views/client/issue/columns.tsx
  19. 32
      src/views/client/issue/data.ts
  20. 294
      src/views/client/issue/formSchemas.tsx
  21. 21
      src/views/client/issue/index.vue
  22. 5
      src/views/dashboard/welcome/index.vue
  23. 23
      src/views/login/index.vue
  24. 1
      src/views/question/issue/columns.tsx
  25. 22
      src/views/question/issue/formSchemas.tsx
  26. 2
      src/views/question/knowledge/columns.tsx
  27. 73
      src/views/system/admin/columns.tsx
  28. 37
      src/views/system/user/columns.tsx
  29. 19
      src/views/system/user/index.vue

2
.env.development

@ -10,7 +10,7 @@
# 网站前缀
VITE_BASE_API_URL = http://192.168.2.92:8089/server/
# VITE_BASE_API_URL = http://43.137.2.78:8082/server/
# VITE_BASE_API_URL = http://43.137.2.78:8085/server/
# base api
VITE_BASE_API = '/server/'

2
.env.production

@ -9,7 +9,7 @@
# 只在生产模式中被载入
# 网站前缀
VITE_BASE_API_URL = http://43.137.2.78:8082/server/
VITE_BASE_API_URL = http://43.137.2.78:8085/server/
# base api
VITE_BASE_API = '/server/'

2
src/api/issue/model.d.ts

@ -26,6 +26,7 @@ declare namespace API {
fileList?: any[]; // 附件列表
tags?: string[] | string; // 标签
solution?: string; // 解决方案
zentaoNos?: string; // 关联的禅道工单号
};
type CreateIssueParams = {
@ -51,6 +52,7 @@ declare namespace API {
fileList?: any[]; // 附件列表
tags?: string[] | string; // 标签
solution?: string; // 解决方案
zentaoNos?: string; // 关联的禅道工单号
};
type DeleteIssueParams = {

22
src/api/user/index.ts

@ -81,6 +81,28 @@ export function updateState(params: { id: string; state: number }) {
});
}
/**
* @description
*/
export function updateAuditState(params: { id: string; auditState: number }) {
return request({
url: `user/updateAuditState`,
method: 'get',
params,
});
}
/**
* @description
*/
export function updateAdminState(params: { id: string; adminState: number }) {
return request({
url: `user/updateAdminState`,
method: 'get',
params,
});
}
/**
* @description
*/

1
src/api/user/model.d.ts

@ -20,6 +20,7 @@ declare namespace API {
createTime: string;
isAdmin: number;
email: string;
auditState?: number;
pendingStatus?: boolean;
};

1
src/assets/icons/audit.svg

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1744789543410" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2661" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M296 250c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H296z m184 144H296c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z m-48 458H208V148h560v320c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V108c0-17.7-14.3-32-32-32H168c-17.7 0-32 14.3-32 32v784c0 17.7 14.3 32 32 32h264c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z m440-88H728v-36.6c46.3-13.8 80-56.6 80-107.4 0-61.9-50.1-112-112-112s-112 50.1-112 112c0 50.7 33.7 93.6 80 107.4V764H520c-8.8 0-16 7.2-16 16v152c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16V780c0-8.8-7.2-16-16-16zM646 620c0-27.6 22.4-50 50-50s50 22.4 50 50-22.4 50-50 50-50-22.4-50-50z m180 266H566v-60h260v60z" fill="#3b82f6" p-id="2662"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

6
src/layout/header/index.vue

@ -2,7 +2,7 @@
<Layout.Header :style="headerStyle" class="layout-header">
<Space :size="20">
<slot>
<Space :size="20" >
<Space :size="20">
<span class="menu-fold flex" @click="() => emit('update:collapsed', !collapsed)">
<component class="" :is="collapsed ? MenuUnfoldOutlined : MenuFoldOutlined" />
</span>
@ -47,6 +47,9 @@
{{ $t('routes.account.settings') }}
</Menu.Item>
<Menu.Divider /> -->
<Menu.Item @click="$router.push({ path:'/entrance' })">
{{ $t('routes.account.goToClient') }}
</Menu.Item>
<Menu.Item>
<div class="flex items-center" @click.prevent="doLogout">
<poweroff-outlined />&nbsp; {{ $t('layout.header.dropdownItemLoginOut') }}
@ -223,6 +226,5 @@
* {
cursor: pointer;
}
}
</style>

1
src/locales/lang/en-US/layout.ts

@ -4,6 +4,7 @@ export default {
// user dropdown
dropdownItemDoc: 'Document',
dropdownItemLoginOut: 'Login Out',
dropdownItemLoginIn: 'Login In',
tooltipErrorLog: 'Error log',
tooltipLock: 'Lock screen',

1
src/locales/lang/en-US/routes/account.ts

@ -1,4 +1,5 @@
export default {
settings: 'settings',
about: 'about',
goToClient: 'go to client',
};

1
src/locales/lang/zh-CN/layout.ts

@ -4,6 +4,7 @@ export default {
// user dropdown
dropdownItemDoc: '文档',
dropdownItemLoginOut: '退出系统',
dropdownItemLoginIn: '去登录',
// tooltip
tooltipErrorLog: '错误日志',

1
src/locales/lang/zh-CN/routes/account.ts

@ -1,4 +1,5 @@
export default {
settings: '个人设置',
about: '关于',
goToClient: '去客户端',
};

2
src/plugins/antd.ts

@ -4,7 +4,7 @@ import { AButton } from '@/components/basic/button/index';
// https://www.antdv.com/docs/vue/getting-started-cn#按需加载
import 'ant-design-vue/es/message/style/css'; //vite只能用 ant-design-vue/es 而非 ant-design-vue/lib
// import 'ant-design-vue/dist/antd.css';
import 'ant-design-vue/dist/antd.css';
import 'ant-design-vue/dist/antd.variable.min.css';
import 'dayjs/locale/zh-cn';

9
src/router/constant.ts

@ -23,7 +23,14 @@ export const whiteNameList = [
'error-404',
] as const; // no redirect whitelist
export const withoutLoginNameList = [LOGIN_NAME, 'icons', 'error', 'error-404'] as const;
export const withoutLoginNameList = [
LOGIN_NAME,
ENTRANCE_NAME,
KNOWLEDGE_NAME,
'icons',
'error',
'error-404',
] as const;
export type WhiteNameList = typeof whiteNameList;

2
src/router/index.ts

@ -12,7 +12,7 @@ export const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Layout',
redirect: '/dashboard/welcome',
redirect: '/entrance',
component: () => import('@/layout/index.vue'),
meta: {
title: '首页',

2
src/router/router-guards.ts

@ -11,7 +11,7 @@ import { to as _to } from '@/utils/awaitTo';
NProgress.configure({ showSpinner: false }); // NProgress Configuration
const defaultRoutePath = '/dashboard/welcome';
const defaultRoutePath = '/entrance';
export function createRouterGuards(router: Router, withoutLoginNameList: WhiteNameList) {
router.beforeEach(async (to, _, next) => {

1
src/store/modules/user.ts

@ -11,6 +11,7 @@ import { generatorDynamicRouter } from '@/router/generator-router';
import { resetRouter } from '@/router';
interface UserState {
id?: string;
token: string;
tokenName: string;
name: string;

73
src/views/client/entrance/index.vue

@ -8,20 +8,23 @@
</div>
<div class="nav-links">
<a-space>
<a href="#" class="nav-item">返回官网</a>
<a class="nav-item" @click="goTo('/question/issue')">返回后台</a>
<!-- <a href="#" class="nav-item">问题社区</a> -->
<!-- <a href="#" class="nav-item">更新日志</a> -->
<a-button type="text" class="favorite">
<!-- <a-button type="text" class="favorite">
<star-outlined />
</a-button>
</a-button> -->
<Dropdown placement="bottomRight">
<Avatar :src="userInfo.headImg" :alt="userInfo.name">{{ userInfo.name }}</Avatar>
<template #overlay>
<Menu>
<Menu.Item>
<div class="flex items-center" @click.prevent="doLogout">
<div v-if="userInfo.id" class="flex items-center" @click.prevent="doLogout">
<poweroff-outlined />&nbsp; {{ $t('layout.header.dropdownItemLoginOut') }}
</div>
<div v-else class="flex items-center" @click.prevent="goToLogin">
<poweroff-outlined />&nbsp; {{ $t('layout.header.dropdownItemLoginIn') }}
</div>
</Menu.Item>
</Menu>
</template>
@ -92,16 +95,16 @@
</div>
</div>
</div>
<div class="search-tags">
<!-- <div class="search-tags">
<a-tag v-for="tag in searchTags" :key="tag.value">{{ tag.label }}</a-tag>
</div>
</div> -->
</div>
<!-- 新手入门区域 -->
<div class="getting-started">
<a-row :gutter="[24, 24]">
<a-col :span="12" v-for="item in startItems" :key="item.title">
<div class="start-card">
<div class="start-card" @click="goTo(item.route)">
<div class="card-content">
<div class="icon-wrapper">
<component :is="item.icon" class="card-icon" />
@ -112,7 +115,7 @@
</div>
</div>
<div class="card-action">
<a-button type="link" @click="goTo(item.route)">立即进入 </a-button>
<a-button type="link">立即进入 </a-button>
</div>
</div>
</a-col>
@ -143,13 +146,14 @@
import { fetchKnowledgeBaseList, findOneById } from '@/api/knowledgeBase';
import { DictEnum } from '@/enums/dictEnum';
import { getDictionaryByTypeName } from '@/utils/dict';
const router = useRouter();
const route = useRoute();
const userStore = useUserStore();
const keepAliveStore = useKeepAliveStore();
const userInfo = computed(() => userStore.userInfo);
const userInfo = ref<any>(userStore.userInfo);
const searchText = ref('');
const searchTags = ref<any>([]);
@ -213,6 +217,16 @@
const goTo = (route: string) => {
console.log(`前往 ${route}`);
if (route === '/issue' && !userInfo.value?.id) {
return Modal.confirm({
title: '访客状态无法查看问题工单,请先登录!',
icon: <QuestionCircleOutlined />,
okText: '去登录',
onOk: async () => {
goToLogin();
},
});
}
router.push(route);
};
@ -227,24 +241,33 @@
icon: <QuestionCircleOutlined />,
centered: true,
onOk: async () => {
// rootadmin退
if (userStore.userInfo.phone !== '13553550634') {
// logout({})
await userStore.logout();
}
keepAliveStore.clear();
//
localStorage.clear();
message.success('成功退出登录');
await nextTick();
router.replace({
userInfo.value = {
name: '访客',
};
// router.replace({
// name: LOGIN_NAME,
// query: {
// redirect: route.fullPath,
// },
// });
},
});
};
const goToLogin = () => {
router.push({
name: LOGIN_NAME,
query: {
redirect: route.fullPath,
},
});
},
});
};
const getTags = async () => {
@ -253,7 +276,13 @@
};
const initData = async () => {
await getTags();
// await getTags();
console.log(' userInfo.value: ', userInfo.value);
if (!userInfo.value?.id) {
userInfo.value = {
name: '访客',
};
}
};
initData();
</script>
@ -281,7 +310,7 @@
}
span {
font-size: 18px;
font-size: 16px;
font-weight: 500;
}
}
@ -331,7 +360,7 @@
margin-bottom: 48px;
h1 {
font-size: 32px;
font-size: 30px;
margin-bottom: 24px;
}
@ -365,7 +394,7 @@
display: flex;
flex-direction: column;
justify-content: space-between;
cursor: pointer;
&:hover {
transform: translateY(-5px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.08);
@ -397,7 +426,7 @@
flex: 1;
h3 {
font-size: 20px;
font-size: 18px;
margin-bottom: 8px;
color: #1f1f1f;
font-weight: 600;
@ -449,7 +478,7 @@
:deep(.ant-input-group-addon) {
background: none;
.ant-btn {
border-radius: 0 24px 24px 0;
border-radius: 0 24px 24px 0 !important;
height: 48px;
}
}

165
src/views/client/issue/columns.tsx

@ -0,0 +1,165 @@
import type { TableColumn } from '@/components/core/dynamic-table';
import { stateTypeList } from './data';
import { Tag } from 'ant-design-vue';
import { DictEnum } from '@/enums/dictEnum';
import { getDictionaryByTypeName } from '@/utils/dict';
export type TableListItem = API.IssueType;
export type TableColumnItem = TableColumn<TableListItem>;
// const questionTypeList = await getDictionaryByTypeName(DictEnum.QUESTION_TYPE);
// 数据项类型
// export type ListItemType = typeof tableData[number];
// 使用TableColumn<ListItemType> 将会限制dataIndex的类型,但换来的是dataIndex有类型提示
export const baseColumns: TableColumnItem[] = [
{
title: '问题标题',
align: 'center',
dataIndex: 'title',
// sorter: true,
width: 150,
resizable: true,
formItemProps: {
defaultValue: '',
required: false,
},
},
{
title: '问题描述',
align: 'center',
dataIndex: 'description',
width: 150,
ellipsis: true,
resizable: true,
formItemProps: {
defaultValue: '',
required: false,
},
},
{
title: '标签',
align: 'center',
dataIndex: 'tags',
width: 200,
hideInSearch: true,
},
// {
// title: '问题属性',
// align: 'center',
// dataIndex: 'attribute',
// width: 150,
// formItemProps: {
// defaultValue: undefined,
// required: false,
// component: 'Select',
// componentProps: {
// options: questionTypeList,
// },
// },
// customRender: ({ record }) => {
// const label = questionTypeList?.find((e) => e.value === record.attribute)?.label;
// return <div>{{ label }}</div>;
// },
// },
{
title: '问题号',
align: 'center',
dataIndex: 'billcode',
width: 200,
formItemProps: {
defaultValue: '',
required: false,
},
},
{
title: '客户',
align: 'center',
dataIndex: 'customer',
width: 150,
hideInSearch: true,
formItemProps: {
defaultValue: '',
required: false,
},
},
{
title: '产品',
align: 'center',
dataIndex: 'product',
width: 150,
hideInSearch: true,
formItemProps: {
defaultValue: '',
required: false,
},
},
{
title: '版本',
align: 'center',
dataIndex: 'version',
width: 150,
hideInSearch: true,
formItemProps: {
defaultValue: '',
required: false,
},
},
{
title: '代理商',
align: 'center',
dataIndex: 'agent',
width: 150,
hideInSearch: true,
formItemProps: {
defaultValue: '',
required: false,
},
},
{
title: '服务号',
align: 'center',
dataIndex: 'serviceNumber',
width: 150,
hideInSearch: true,
formItemProps: {
defaultValue: '',
required: false,
},
},
{
title: '创建时间',
align: 'center',
width: 200,
dataIndex: 'createTime',
formItemProps: {
defaultValue: '',
required: false,
component: 'RangePicker',
componentProps: {
valueFormat: 'YYYY-MM-DD',
},
},
},
// state 问题状态
{
title: '问题状态',
align: 'center',
dataIndex: 'state',
width: 150,
fixed: 'right',
formItemProps: {
defaultValue: undefined,
required: false,
component: 'Select',
componentProps: {
options: stateTypeList,
},
},
customRender: ({ record }) => {
const { label, color } = stateTypeList.find((e) => e.value === record.state);
return <Tag color={color}>{label}</Tag>;
},
},
];

32
src/views/client/issue/data.ts

@ -0,0 +1,32 @@
export const stateTypeList: any = [
// Init(0,"待处理"),
// Back(1,"退回"),
// Develop(2,"开发中"),
// Test(3,"测试中"),
// End(4,"结束"),
{
label: '待处理',
value: 0,
color: '#f50',
},
{
label: '退回',
value: 1,
color: '#2db7f5',
},
{
label: '开发中',
value: 2,
color: '#87d068',
},
{
label: '测试中',
value: 3,
color: '#108ee9',
},
{
label: '已解决',
value: 4,
color: '#f50',
},
];

294
src/views/client/issue/formSchemas.tsx

@ -0,0 +1,294 @@
import type { FormSchema } from '@/components/core/schema-form/';
import { TableListItem } from './columns';
import { commonUpload } from '@/api/upload';
import { message, Button } from 'ant-design-vue';
import { getFileExtension } from '@/utils/fileUtils';
import { UploadOutlined } from '@ant-design/icons-vue';
import { stateTypeList } from './data';
import { DictEnum } from '@/enums/dictEnum';
import { getDictionaryByTypeName } from '@/utils/dict';
import { fetchProdList, fetchVersionPageList } from '@/api/prodVersion';
import { vShow } from 'vue';
const questionTypeList = await getDictionaryByTypeName(DictEnum.QUESTION_TYPE);
// 编辑页字段
export const getEditFormSchema: (
row?: Partial<TableListItem>,
isDetail?: boolean,
) => FormSchema[] = (record = {}, isDetail = false) => {
console.log('questionTypeList: ', questionTypeList);
return [
{
field: 'billcode',
component: 'Input',
label: '问题号',
dynamicDisabled: true,
colProps: {
span: 24,
},
},
{
field: 'title',
component: 'Input',
componentProps: {
showCount: true,
maxlength: 150,
},
label: '问题标题',
colProps: {
span: 12,
},
rules: [{ required: true }],
},
{
field: 'tags',
component: 'Select',
componentProps: {
request: async () => {
const data = await getDictionaryByTypeName(DictEnum.TAG_TYPE);
return data;
},
multiple: true,
placeholder: '请选择标签',
mode: 'tags',
allowClear: true,
},
label: '标签',
colProps: {
span: 12,
},
rules: [{ required: true, type: 'array' }],
},
// {
// label: '问题属性',
// field: 'arrtibute',
// component: 'Select',
// componentProps: {
// options: questionTypeList,
// },
// colProps: {
// span: 12,
// },
// rules: [{ required: true, type: 'string' }],
// },
{
field: 'customer',
component: 'Input',
label: '客户',
colProps: {
span: 12,
},
},
{
field: 'productId',
component: 'Select',
componentProps: ({ formModel, formInstance }) => {
return {
request: async () => {
const data = (await fetchProdList({})) as any;
return data.map((e) => {
return {
label: e.name,
value: e.id,
};
});
},
onChange: async (e) => {
console.log('e: ', e);
const { data } = await fetchVersionPageList({
productId: e,
current: 1,
size: 999,
});
if (data && Array.isArray(data) && data.length) {
formInstance?.setFieldsValue({
versionId: data[0].id,
});
formInstance.updateSchema({
field: 'versionId',
componentProps: {
options: data.map((e) => {
return {
label: e.name,
value: e.id,
};
}),
},
});
}
},
};
},
label: '产品',
colProps: {
span: 12,
},
rules: [{ required: true, type: 'number' }],
},
{
field: 'versionId',
component: 'Select',
componentProps: {
options: [],
},
label: '版本',
colProps: {
span: 12,
},
rules: [{ required: true, type: 'number' }],
},
{
field: 'agent',
component: 'Input',
label: '代理商',
colProps: {
span: 12,
},
},
{
field: 'serviceNumber',
component: 'Input',
label: '服务号',
colProps: {
span: 12,
},
},
{
field: 'contacts',
component: 'Input',
label: '联系人',
colProps: {
span: 12,
},
rules: [{ required: true, type: 'string' }],
},
{
field: 'contactsEmail',
component: 'Input',
label: '联系人邮箱',
colProps: {
span: 12,
},
rules: [{ required: true, type: 'string' }],
},
{
field: 'contactsMobile',
component: 'Input',
label: '联系人手机号',
colProps: {
span: 12,
},
rules: [
{
required: true,
message: '请输入正确格式的电话号码',
pattern:
/^(1(3[0-9]|4[01456879]|5[0-3,5-9]|6[2567]|7[0-8]|8[0-9]|9[0-3,5-9])\d{8})$|^0\d{2,3}-?\d{7,8}$/,
},
],
},
// {
// field: 'state',
// component: 'Select',
// defaultValue: 0,
// label: '状态',
// colProps: {
// span: 12,
// },
// componentProps: {
// options: stateTypeList,
// disabled: true,
// },
// rules: [{ required: true, type: 'number' }],
// },
{
field: 'description',
component: 'InputTextArea',
componentProps: {
rows: 4,
placeholder: '请输入问题描述',
showCount: true,
maxlength: 150,
},
label: '问题描述',
colProps: {
span: 24,
},
rules: [{ required: true }],
},
{
label: '描述附件',
field: 'files',
component: 'Upload',
componentProps: {
disabled: isDetail,
customRequest: async (data) => {
console.log('data: ', data);
const formData = new FormData();
formData.append('file', data.file);
const res = await commonUpload(formData);
console.log('res: ', res);
data?.onSuccess && data?.onSuccess(res, data.file as any);
},
beforeUpload: (file) => {
console.log('file: ', file);
// 限制允许上传的文件类型
const allowedTypes = ['xlsx', 'xls', 'doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png'];
// 检查文件类型
const fileType = getFileExtension(file.name) || 'unknown';
if (!allowedTypes.includes(fileType)) {
// 文件类型不在允许列表中,拒绝上传
// 可以在这里展示错误信息
message.warning('文件类型不正确');
return false;
}
// 其他验证逻辑...
// 允许上传
return true;
},
},
componentSlots: {
default: () => (
<Button>
<UploadOutlined />
</Button>
),
},
colProps: {
span: 24,
},
rules: [{ required: false }],
},
{
label: '解决方案',
field: 'solution',
colProps: {
span: 24,
},
vShow: isDetail,
// rules: [{ required: true, type: 'array' }],
slot: 'solution',
},
] as any;
};
export const getFlowFormSchema: (row?: Partial<TableListItem>) => FormSchema[] = (record = {}) => {
return [
{
field: 'remark',
component: 'InputTextArea',
label: '文字补充内容',
colProps: {
span: 24,
},
},
];
};

21
src/views/client/issue/index.vue

@ -132,7 +132,7 @@
import Detail from '@/views/question/issue/detail.vue';
import { DraggableModal } from '@/components/core/draggable-modal';
import { useForm } from '@/components/core/schema-form';
import { getEditFormSchema } from '@/views/question/issue/formSchemas.tsx';
import { getEditFormSchema } from './formSchemas.tsx';
import { QuillEditor } from '@vueup/vue-quill';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { type TableListItem } from '@/views/question/issue/columns';
@ -205,13 +205,13 @@
handleAdd();
},
},
{
title: '编辑工单',
icon: EditOutlined,
onClick: () => {
handleEdit(curRow.value);
},
},
// {
// title: '',
// icon: EditOutlined,
// onClick: () => {
// handleEdit(curRow.value);
// },
// },
// {
// title: '',
// icon: DeleteOutlined,
@ -258,6 +258,11 @@
values.tags = values.tags.join(',');
}
//
if (!values.id) {
values.state = 0;
}
await (values.id ? updateIssue : createIssue)(values);
message.success(`${values.id ? '编辑' : '新增'}成功`);
visible.value = false;

5
src/views/dashboard/welcome/index.vue

@ -7,7 +7,7 @@
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<svg-icon name="icon-wangpan" size="50"></svg-icon>
<!-- <svg-icon name="icon-wangpan" size="50"></svg-icon>
<div class="welcome-container">
<a-card class="doc-card">
@ -17,10 +17,9 @@
<a-tag color="blue">DTO</a-tag>
</div>
</template>
<!-- <div class="markdown-body" v-html="mdContent"></div> -->
<DTO></DTO>
</a-card>
</div>
</div> -->
</template>
<script lang="ts" setup>

23
src/views/login/index.vue

@ -118,6 +118,7 @@
state.formInline.username = '';
state.formInline.password = '';
state.formInline.confirmPassword = '';
state.formInline.email = '';
};
//
@ -132,17 +133,23 @@
if (password !== confirmPassword) {
return message.warning('两次输入的密码不一致!');
}
if (state.formInline.email.trim() === '') {
return message.warning('邮箱不能为空!');
}
if (!/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(state.formInline.email)) {
return message.warning('请输入有效的邮箱地址!');
}
// TODO:
message.loading('注册中...', 0);
state.loading = true;
try {
await register({
...state.formInline,
account: state.formInline.username,
});
message.success('注册成功!');
message.success('注册成功,请联系系统管理员通过审核');
setTimeout(() => {
state.isRegister = false; //
}, 1000);
} catch (err: any) {
Modal.error({
title: '提示',
@ -150,7 +157,6 @@
});
}
state.loading = false;
message.destroy();
return;
}
@ -195,8 +201,9 @@
display: flex;
width: 100vw;
height: 100vh;
background: url('@/assets/images/background.jpg') no-repeat center center fixed;
background-size: cover;
// background: url('@/assets/images/background.jpg') no-repeat center center fixed;
// background-size: cover;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
// background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
align-items: center;
justify-content: center;
@ -297,7 +304,7 @@
}
.login-title {
font-size: 32px;
font-size: 30px;
font-weight: 700;
background: linear-gradient(135deg, #e6400b 0%, #ec7049 100%);
-webkit-background-clip: text;
@ -332,7 +339,7 @@
}
.login-subtitle {
font-size: 16px;
font-size: 15px;
color: #666;
margin: 0;
font-weight: 500;

1
src/views/question/issue/columns.tsx

@ -29,6 +29,7 @@ export const baseColumns: TableColumnItem[] = [
align: 'center',
dataIndex: 'description',
width: 150,
ellipsis: true,
resizable: true,
formItemProps: {
defaultValue: '',

22
src/views/question/issue/formSchemas.tsx

@ -123,6 +123,7 @@ export const getEditFormSchema: (
colProps: {
span: 12,
},
rules: [{ required: true, type: 'number' }],
},
{
field: 'versionId',
@ -134,6 +135,7 @@ export const getEditFormSchema: (
colProps: {
span: 12,
},
rules: [{ required: true, type: 'number' }],
},
{
field: 'agent',
@ -152,6 +154,14 @@ export const getEditFormSchema: (
span: 12,
},
},
{
field: 'zentaoNos',
component: 'Input',
label: '禅道号',
colProps: {
span: 12,
},
},
{
field: 'contacts',
component: 'Input',
@ -159,6 +169,7 @@ export const getEditFormSchema: (
colProps: {
span: 12,
},
rules: [{ required: true, type: 'string' }],
},
{
field: 'contactsEmail',
@ -167,6 +178,13 @@ export const getEditFormSchema: (
colProps: {
span: 12,
},
rules: [
{
required: true,
message: '请输入正确格式的邮箱',
pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
},
],
},
{
field: 'contactsMobile',
@ -177,7 +195,7 @@ export const getEditFormSchema: (
},
rules: [
{
required: false,
required: true,
message: '请输入正确格式的电话号码',
pattern:
/^(1(3[0-9]|4[01456879]|5[0-3,5-9]|6[2567]|7[0-8]|8[0-9]|9[0-3,5-9])\d{8})$|^0\d{2,3}-?\d{7,8}$/,
@ -194,6 +212,7 @@ export const getEditFormSchema: (
},
componentProps: {
options: stateTypeList,
disabled: true,
},
rules: [{ required: true, type: 'number' }],
},
@ -266,7 +285,6 @@ export const getEditFormSchema: (
colProps: {
span: 24,
},
// vShow: !isDetail,
// rules: [{ required: true, type: 'array' }],
slot: 'solution',
},

2
src/views/question/knowledge/columns.tsx

@ -22,6 +22,7 @@ export const baseColumns: TableColumnItem[] = [
title: '描述',
align: 'center',
dataIndex: 'description',
ellipsis: true,
width: 150,
resizable: true,
formItemProps: {
@ -29,7 +30,6 @@ export const baseColumns: TableColumnItem[] = [
required: false,
},
},
{
title: '标签',
align: 'center',

73
src/views/system/admin/columns.tsx

@ -1,7 +1,8 @@
import { debounce } from 'lodash-es';
import type { TableColumn } from '@/components/core/dynamic-table';
import { formatToDateTime } from '@/utils/dateUtil';
import { updateUser } from '@/api/user';
import { updateState, updateAdminState } from '@/api/user';
import { h } from 'vue';
import { Switch } from 'ant-design-vue';
import { sexTypeList } from './data';
@ -81,11 +82,11 @@ export const baseColumns: TableColumnItem[] = [
options: [
{
label: '启用',
value: 1,
value: 0,
},
{
label: '禁用',
value: 0,
value: 1,
},
],
},
@ -94,9 +95,12 @@ export const baseColumns: TableColumnItem[] = [
const onChange = (checked: boolean) => {
console.log('checked: ', checked);
record.pendingStatus = true;
const newState = checked ? 1 : 0;
const newState = checked ? 0 : 1;
record.state = newState;
updateUser(record)
updateState({
id: record.id!,
state: newState,
})
.then(() => {
record.state = newState;
})
@ -105,16 +109,10 @@ export const baseColumns: TableColumnItem[] = [
record.pendingStatus = false;
});
};
// return (
// <a-switch
// v-model:checked={record.state}
// v-model:loading={record.pendingStatus}
// onChange={onChange}
// ></a-switch>
// );
// 渲染函数写法
return h(Switch, {
checked: record.state === 1 ? true : false,
checked: record.state === 0 ? true : false,
loading: record.pendingStatus,
onChange,
});
@ -147,7 +145,10 @@ export const baseColumns: TableColumnItem[] = [
record.pendingStatus = true;
const newState = checked ? 1 : 0;
record.isAdmin = newState;
updateUser(record)
updateAdminState({
id: record.id!,
adminState: newState,
})
.then(() => {
record.isAdmin = newState;
})
@ -156,13 +157,7 @@ export const baseColumns: TableColumnItem[] = [
record.pendingStatus = false;
});
};
// return (
// <a-switch
// v-model:checked={record.state}
// v-model:loading={record.pendingStatus}
// onChange={onChange}
// ></a-switch>
// );
// 渲染函数写法
return h(Switch, {
checked: record.isAdmin === 1 ? true : false,
@ -256,11 +251,11 @@ export const getBaseColumns = (tableInstance) => {
options: [
{
label: '启用',
value: 1,
value: 0,
},
{
label: '禁用',
value: 0,
value: 1,
},
],
},
@ -269,28 +264,24 @@ export const getBaseColumns = (tableInstance) => {
const onChange = (checked: boolean) => {
console.log('checked: ', checked);
record.pendingStatus = true;
const newState = checked ? 1 : 0;
const newState = checked ? 0 : 1;
record.state = newState;
updateUser(record)
updateState({
id: record.id!,
state: newState,
})
.then(() => {
record.state = newState;
})
.catch(() => {})
.finally(() => {
record.pendingStatus = false;
tableInstance && tableInstance?.reload();
});
};
// return (
// <a-switch
// v-model:checked={record.state}
// v-model:loading={record.pendingStatus}
// onChange={onChange}
// ></a-switch>
// );
// 渲染函数写法
return h(Switch, {
checked: record.state === 1 ? true : false,
checked: record.state === 0 ? true : false,
loading: record.pendingStatus,
onChange,
});
@ -323,23 +314,19 @@ export const getBaseColumns = (tableInstance) => {
record.pendingStatus = true;
const newState = checked ? 1 : 0;
record.isAdmin = newState;
updateUser(record)
updateAdminState({
id: record.id!,
adminState: newState,
})
.then(() => {
record.isAdmin = newState;
})
.catch(() => {})
.finally(() => {
record.pendingStatus = false;
tableInstance && tableInstance?.reload();
});
};
// return (
// <a-switch
// v-model:checked={record.state}
// v-model:loading={record.pendingStatus}
// onChange={onChange}
// ></a-switch>
// );
// 渲染函数写法
return h(Switch, {
checked: record.isAdmin === 1 ? true : false,

37
src/views/system/user/columns.tsx

@ -1,9 +1,9 @@
import { debounce } from 'lodash-es';
import type { TableColumn } from '@/components/core/dynamic-table';
import { formatToDateTime } from '@/utils/dateUtil';
import { updateUser, updateState } from '@/api/user';
import { updateUser, updateState, updateAdminState } from '@/api/user';
import { h } from 'vue';
import { Switch } from 'ant-design-vue';
import { Switch, Tag } from 'ant-design-vue';
import { sexTypeList } from './data';
export type TableListItem = API.UserInfoType;
export type TableColumnItem = TableColumn<TableListItem>;
@ -77,6 +77,18 @@ export const baseColumns: TableColumnItem[] = [
return <div>{text}</div>;
},
},
{
title: '审核状态',
align: 'center',
width: 100,
dataIndex: 'auditState',
hideInSearch: true,
customRender: ({ record }) => {
const text = record.auditState === 0 ? '未审核' : '审核通过',
color = record.auditState === 0 ? 'red' : 'green';
return <Tag color={color}>{text}</Tag>;
},
},
{
title: '帐号状态',
align: 'center',
@ -116,13 +128,7 @@ export const baseColumns: TableColumnItem[] = [
record.pendingStatus = false;
});
};
// return (
// <a-switch
// v-model:checked={record.state}
// v-model:loading={record.pendingStatus}
// onChange={onChange}
// ></a-switch>
// );
// 渲染函数写法
return h(Switch, {
checked: record.state === 0 ? true : false,
@ -158,7 +164,10 @@ export const baseColumns: TableColumnItem[] = [
record.pendingStatus = true;
const newState = checked ? 1 : 0;
record.isAdmin = newState;
updateUser(record)
updateAdminState({
id: record.id!,
adminState: newState,
})
.then(() => {
record.isAdmin = newState;
})
@ -167,13 +176,7 @@ export const baseColumns: TableColumnItem[] = [
record.pendingStatus = false;
});
};
// return (
// <a-switch
// v-model:checked={record.state}
// v-model:loading={record.pendingStatus}
// onChange={onChange}
// ></a-switch>
// );
// 渲染函数写法
return h(Switch, {
checked: record.isAdmin === 1 ? true : false,

19
src/views/system/user/index.vue

@ -53,6 +53,7 @@
findOneById,
deleteUserById,
deleteBatchUserById,
updateAuditState,
} from '@/api/user';
import { computed, reactive, ref, toRaw } from 'vue';
import { Modal, message, Alert } from 'ant-design-vue';
@ -90,6 +91,14 @@
label: '修改',
onClick: () => handleEdit(record),
},
{
icon: 'audit',
color: '#3b82f6',
size: '18',
label: '审核通过',
vShow: record.auditState === 0,
onClick: () => handleAudit(record),
},
{
icon: 'delete',
color: '#ec6f6f',
@ -134,6 +143,14 @@
// }
};
const handleAudit = async (record: TableListItem) => {
const { id } = record;
if (!id) return;
const res = await updateAuditState({ id, auditState: 1 });
message.success('审核成功');
dynamicTableInstance?.reload();
};
const handleEdit = (record: TableListItem) => {
openUserModal(record);
};
@ -155,7 +172,7 @@
icon: <ExclamationCircleOutlined />,
centered: true,
onOk: async () => {
await deleteBatchUserById( ids ).finally(dynamicTableInstance?.reload);
await deleteBatchUserById(ids).finally(dynamicTableInstance?.reload);
},
});
};

Loading…
Cancel
Save