关闭TS校验和完善票据查询功能

This commit is contained in:
2024-05-29 10:03:12 +08:00
parent 4f05a4b12e
commit 69fd1b6b88
23 changed files with 368 additions and 389 deletions

View File

@ -36,7 +36,7 @@ module.exports = {
}, },
}, },
rules: { rules: {
'prettier/prettier': 1, 'prettier/prettier': 0,
// Vue: Recommended rules to be closed or modify // Vue: Recommended rules to be closed or modify
'vue/require-default-prop': 0, 'vue/require-default-prop': 0,
'vue/singleline-html-element-content-newline': 0, 'vue/singleline-html-element-content-newline': 0,

View File

@ -14,7 +14,6 @@ export default mergeConfig(
proxy: { proxy: {
'/api': { '/api': {
target: 'http://106.53.179.133:8081', target: 'http://106.53.179.133:8081',
// target: 'http://192.168.243.246:8081',
// target: 'http://localhost:5173', // target: 'http://localhost:5173',
changeOrigin: true, changeOrigin: true,
}, },

View File

@ -1,8 +1,7 @@
import axios from 'axios'; import axios from 'axios';
import type { AxiosRequestConfig, AxiosResponse } from 'axios'; import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import { Message, Modal } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { getToken } from '@/utils/auth'; import { getToken } from '@/utils/auth';
import { useUserStore } from '@/store';
import router from '@/router'; import router from '@/router';
export interface HttpResponse<T = unknown> { export interface HttpResponse<T = unknown> {
@ -73,7 +72,7 @@ axios.interceptors.response.use(
}, },
(error) => { (error) => {
const { response } = error; const { response } = error;
console.log('error', error); // console.log('error', error);
if (response.status === 401) { if (response.status === 401) {

View File

@ -6,6 +6,11 @@
<a-typography-title <a-typography-title
:style="{ margin: 0, fontSize: '18px' }" :style="{ margin: 0, fontSize: '18px' }"
:heading="5" :heading="5"
@click="
{
router.push({ name: 'Workplace' });
}
"
> >
{{ $t('ticket.manage.system') }} {{ $t('ticket.manage.system') }}
</a-typography-title> </a-typography-title>
@ -107,6 +112,9 @@
</a-tooltip> </a-tooltip>
</li> </li>
<li>
<a-button status="normal">{{ userStore.permissions }}</a-button>
</li>
<li> <li>
<a-dropdown trigger="click"> <a-dropdown trigger="click">
<a-button style="margin-right: 20px" status="normal">{{ <a-button style="margin-right: 20px" status="normal">{{
@ -153,17 +161,16 @@ import { useDark, useToggle, useFullscreen } from '@vueuse/core';
import { useAppStore, useUserStore } from '@/store'; import { useAppStore, useUserStore } from '@/store';
import { LOCALE_OPTIONS } from '@/locale'; import { LOCALE_OPTIONS } from '@/locale';
import useLocale from '@/hooks/locale'; import useLocale from '@/hooks/locale';
import useUser from '@/hooks/user';
import Menu from '@/components/menu/index.vue'; import Menu from '@/components/menu/index.vue';
import userIcon from '@/assets/images/user-circle.png'; import userIcon from '@/assets/images/user-circle.png';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { clearToken } from '@/utils/auth'; import { clearToken } from '@/utils/auth';
import MessageBox from '../message-box/index.vue';
const router = useRouter(); const router = useRouter();
const appStore = useAppStore(); const appStore = useAppStore();
const userStore = useUserStore(); const userStore = useUserStore();
const { logout } = useUser();
const { changeLocale, currentLocale } = useLocale(); const { changeLocale, currentLocale } = useLocale();
const { isFullscreen, toggle: toggleFullScreen } = useFullscreen(); const { isFullscreen, toggle: toggleFullScreen } = useFullscreen();
const locales = [...LOCALE_OPTIONS]; const locales = [...LOCALE_OPTIONS];
@ -192,18 +199,9 @@ const handleToggleTheme = () => {
const setVisible = () => { const setVisible = () => {
appStore.updateSettings({ globalSettings: true }); appStore.updateSettings({ globalSettings: true });
}; };
const refBtn = ref();
const triggerBtn = ref();
const defaultRole = ref(userStore.role?.id);
const setPopoverVisible = () => { const triggerBtn = ref();
const event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true,
});
refBtn.value.dispatchEvent(event);
};
const handleLogout = () => { const handleLogout = () => {
clearToken(); clearToken();
router.push({ router.push({

View File

@ -2,14 +2,12 @@ import type { Router, RouteRecordNormalized } from 'vue-router';
import NProgress from 'nprogress'; // progress bar import NProgress from 'nprogress'; // progress bar
import usePermission from '@/hooks/permission'; import usePermission from '@/hooks/permission';
import { useUserStore, useAppStore } from '@/store'; import { useAppStore } from '@/store';
import { appRoutes } from '../routes';
import { WHITE_LIST, NOT_FOUND } from '../constants'; import { WHITE_LIST, NOT_FOUND } from '../constants';
export default function setupPermissionGuard(router: Router) { export default function setupPermissionGuard(router: Router) {
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const appStore = useAppStore(); const appStore = useAppStore();
const userStore = useUserStore();
const Permission = usePermission(); const Permission = usePermission();
const permissionsAllow = Permission.accessRouter(to); const permissionsAllow = Permission.accessRouter(to);

View File

@ -6,7 +6,6 @@ import {
LoginData, LoginData,
me, me,
queryUserList, queryUserList,
UserParams,
enabled, enabled,
remove, remove,
create, create,
@ -72,7 +71,7 @@ const useUserStore = defineStore('user', {
async login(loginForm: LoginData, token: string) { async login(loginForm: LoginData, token: string) {
try { try {
setToken(token); setToken(token);
const res = await userLogin(loginForm); await userLogin(loginForm);
} catch (err) { } catch (err) {
clearToken(); clearToken();
throw err; throw err;

View File

@ -2,7 +2,6 @@
import saveAs from 'file-saver'; // https://www.npmjs.com/package/file-saver import saveAs from 'file-saver'; // https://www.npmjs.com/package/file-saver
import ExcelJS from 'exceljs'; // https://github.com/exceljs/exceljs/blob/master/README_zh.md import ExcelJS from 'exceljs'; // https://github.com/exceljs/exceljs/blob/master/README_zh.md
import dayjs from 'dayjs'; // https://dayjs.fenxianglu.cn/
import * as XLSX from 'xlsx'; // https://www.npmjs.com/package/xlsx import * as XLSX from 'xlsx'; // https://www.npmjs.com/package/xlsx
import { Message } from '@arco-design/web-vue'; // https://arco.design/vue/component/message import { Message } from '@arco-design/web-vue'; // https://arco.design/vue/component/message
import { FileItem } from '@arco-design/web-vue/es/upload/interfaces'; // arco类型 import { FileItem } from '@arco-design/web-vue/es/upload/interfaces'; // arco类型
@ -44,7 +43,6 @@ export function downloadExcel({ columns, rows, name = '未命名文件' }: Downl
// 读取文件为json格式 // 读取文件为json格式
export function readExcle(fileItem:FileItem) { export function readExcle(fileItem:FileItem) {
console.log('读取文件...',fileItem);
return new Promise((resove,reject)=>{ return new Promise((resove,reject)=>{
try { try {
let workbook:XLSX.Sheet; let workbook:XLSX.Sheet;

View File

@ -5,7 +5,7 @@
class="panel-col" class="panel-col"
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }" :span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
> >
<a-space> <a-space @click="to('PASS')">
<a-avatar :size="54" class="col-avatar"> <a-avatar :size="54" class="col-avatar">
<img <img
alt="avatar" alt="avatar"
@ -16,7 +16,6 @@
:title="$t('workplace.pass')" :title="$t('workplace.pass')"
:value="formData.pass || 0" :value="formData.pass || 0"
:value-from="0" :value-from="0"
animation
show-group-separator show-group-separator
> >
<template #suffix> <template #suffix>
@ -29,7 +28,7 @@
class="panel-col" class="panel-col"
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }" :span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
> >
<a-space> <a-space @click="to('FAILED')">
<a-avatar :size="54" class="col-avatar"> <a-avatar :size="54" class="col-avatar">
<img <img
alt="avatar" alt="avatar"
@ -40,7 +39,6 @@
:title="$t('workplace.notPass')" :title="$t('workplace.notPass')"
:value="formData.notPass || 0" :value="formData.notPass || 0"
:value-from="0" :value-from="0"
animation
show-group-separator show-group-separator
> >
<template #suffix> <template #suffix>
@ -53,7 +51,7 @@
class="panel-col" class="panel-col"
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }" :span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
> >
<a-space> <a-space @click="to('EXAMINE')">
<a-avatar :size="54" class="col-avatar"> <a-avatar :size="54" class="col-avatar">
<img <img
alt="avatar" alt="avatar"
@ -64,7 +62,6 @@
:title="$t('workplace.notAudit')" :title="$t('workplace.notAudit')"
:value="formData.notAudit || 0" :value="formData.notAudit || 0"
:value-from="0" :value-from="0"
animation
show-group-separator show-group-separator
> >
<template #suffix> <template #suffix>
@ -79,7 +76,7 @@
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }" :span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
style="border-right: none" style="border-right: none"
> >
<a-space> <a-space @click="to('SUBMIT')">
<a-avatar :size="54" class="col-avatar"> <a-avatar :size="54" class="col-avatar">
<img <img
alt="avatar" alt="avatar"
@ -91,7 +88,6 @@
:title="$t('workplace.notFiled')" :title="$t('workplace.notFiled')"
:value="formData.notFiled || 0" :value="formData.notFiled || 0"
:value-from="0" :value-from="0"
animation
show-group-separator show-group-separator
> >
<template #suffix> <template #suffix>
@ -104,7 +100,7 @@
<a-divider class="panel-border" /> <a-divider class="panel-border" />
</a-grid-item> </a-grid-item>
</a-grid> </a-grid>
<a-card :bordered="false" v-if="userStore.permissions === 'admin'"> <a-card :bordered="false">
<a-space id="TicketEcharts" style="width: 98%; height: 400px"></a-space> <a-space id="TicketEcharts" style="width: 98%; height: 400px"></a-space>
</a-card> </a-card>
</div> </div>
@ -115,6 +111,7 @@ import { useI18n } from 'vue-i18n';
import { useTicketStore, useUserStore } from '@/store'; import { useTicketStore, useUserStore } from '@/store';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import router from '@/router';
const { t } = useI18n(); const { t } = useI18n();
const ticketStore = useTicketStore(); const ticketStore = useTicketStore();
@ -126,14 +123,8 @@ const formData = ref({
pass: undefined, pass: undefined,
}); });
const getEchartData = () => {
const res = ticketStore.getChart();
console.log('chart', res);
};
onMounted(async () => { onMounted(async () => {
const res = await ticketStore.getChart(); const res = await ticketStore.getChart();
console.log('chart', res.data);
type EChartsOption = echarts.EChartsOption; type EChartsOption = echarts.EChartsOption;
const chartDom = document.getElementById('TicketEcharts'); const chartDom = document.getElementById('TicketEcharts');
const myChart = echarts.init(chartDom); const myChart = echarts.init(chartDom);
@ -208,6 +199,15 @@ const getHomeData = async (params: {
formData.value = res.data; formData.value = res.data;
}); });
}; };
const to = (key: string) => {
router.push({
name: 'TicketManage',
query: {
status: key,
},
});
};
getHomeData({}); getHomeData({});
</script> </script>

View File

@ -192,7 +192,6 @@ import { useStorage } from '@vueuse/core';
import { useUserStore } from '@/store'; import { useUserStore } from '@/store';
import useLoading from '@/hooks/loading'; import useLoading from '@/hooks/loading';
import { LoginData, CreateRecord } from '@/api/user'; import { LoginData, CreateRecord } from '@/api/user';
import { deptList } from '@/api/dept';
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
@ -219,11 +218,6 @@ const formData = ref<CreateRecord>({
const flag = ref(false); const flag = ref(false);
const totalCount = ref(60); const totalCount = ref(60);
const deptOptions = ref();
const getDeptData = async () => {
const res = await deptList();
deptOptions.value = res.data.records;
};
const loginConfig = useStorage('login-config', { const loginConfig = useStorage('login-config', {
// 使 useStorage // 使 useStorage
@ -257,10 +251,10 @@ const handleSubmit = async ({
try { try {
const res = await userStore.me(); const res = await userStore.me();
await userStore.login(values as LoginData, res.data.csrf.token); await userStore.login(values as LoginData, res.data.csrf.token);
const csrf = await userStore.me(); await userStore.me();
await userStore.info(); await userStore.info();
// //
const { redirect, ...othersQuery } = router.currentRoute.value.query; const { ...othersQuery } = router.currentRoute.value.query;
router.push({ router.push({
name: 'Workplace', name: 'Workplace',
query: { query: {

View File

@ -48,8 +48,8 @@ import { useI18n } from 'vue-i18n';
import useVisible from '@/hooks/visible'; import useVisible from '@/hooks/visible';
import { computed, PropType, ref } from 'vue'; import { computed, PropType, ref } from 'vue';
import { FormInstance } from '@arco-design/web-vue/es/form'; import { FormInstance } from '@arco-design/web-vue/es/form';
import { Message, TreeNodeData } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { DeptRecord, DeptCreateRecord } from '@/api/dept'; import { DeptRecord } from '@/api/dept';
import { useDeptStore } from '@/store'; import { useDeptStore } from '@/store';
const props = defineProps({ const props = defineProps({

View File

@ -163,12 +163,12 @@
<a-pagination <a-pagination
style="float: right; position: relative; right: 1px; bottom: 25px" style="float: right; position: relative; right: 1px; bottom: 25px"
:total="pagination.total" :total="pagination.total"
@page-size-change="onSizeChange"
:size="size" :size="size"
@change="onPageChange"
show-total show-total
show-jumper show-jumper
show-page-size show-page-size
@page-size-change="onSizeChange"
@change="onPageChange"
/> />
</a-card> </a-card>
</div> </div>

View File

@ -50,7 +50,6 @@ import { useI18n } from 'vue-i18n';
import useVisible from '@/hooks/visible'; import useVisible from '@/hooks/visible';
import { computed, PropType, ref } from 'vue'; import { computed, PropType, ref } from 'vue';
import { FormInstance } from '@arco-design/web-vue/es/form'; import { FormInstance } from '@arco-design/web-vue/es/form';
import { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { RoleRecord } from '@/api/role'; import { RoleRecord } from '@/api/role';
import { useRoleStore } from '@/store'; import { useRoleStore } from '@/store';

View File

@ -115,8 +115,8 @@
:data="renderData" :data="renderData"
:bordered="false" :bordered="false"
:size="size" :size="size"
@page-change="onPageChange"
style="margin-bottom: 40px" style="margin-bottom: 40px"
@page-change="onPageChange"
> >
<template #index="{ rowIndex }"> <template #index="{ rowIndex }">
{{ rowIndex + 1 }} {{ rowIndex + 1 }}
@ -160,19 +160,19 @@
<a-pagination <a-pagination
style="float: right; position: relative; right: 1px; bottom: 25px" style="float: right; position: relative; right: 1px; bottom: 25px"
:total="pagination.total" :total="pagination.total"
@page-size-change="onSizeChange"
:size="size" :size="size"
@change="onPageChange"
show-total show-total
show-jumper show-jumper
show-page-size show-page-size
@page-size-change="onSizeChange"
@change="onPageChange"
/> />
</a-card> </a-card>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref, reactive, watch, nextTick } from 'vue'; import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import useLoading from '@/hooks/loading'; import useLoading from '@/hooks/loading';
import { Pagination } from '@/types/global'; import { Pagination } from '@/types/global';
@ -181,11 +181,9 @@ import { Message } from '@arco-design/web-vue';
import useTableOption from '@/hooks/table-option'; import useTableOption from '@/hooks/table-option';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useRoleStore } from '@/store'; import { useRoleStore } from '@/store';
import { RoleRecord, RoleCreateRecord } from '@/api/role'; import { RoleRecord } from '@/api/role';
import RoleEdit from './components/role-edit.vue'; import RoleEdit from './components/role-edit.vue';
type SizeProps = 'mini' | 'small' | 'medium' | 'large';
type Column = TableColumnData & { checked?: true };
const { loading, setLoading } = useLoading(true); const { loading, setLoading } = useLoading(true);
const { t } = useI18n(); const { t } = useI18n();
const renderData = ref<RoleRecord[]>([]); const renderData = ref<RoleRecord[]>([]);
@ -257,7 +255,6 @@ const fetchData = async (params: any) => {
setLoading(true); setLoading(true);
try { try {
const res = await roleStore.getRoleList(params); const res = await roleStore.getRoleList(params);
console.log('info', res.data);
renderData.value = res.data.records; renderData.value = res.data.records;
pagination.page = res.data.page; pagination.page = res.data.page;
pagination.current = res.data.current; pagination.current = res.data.current;

View File

@ -85,7 +85,7 @@
<a-space> <a-space>
<UserEdit ref="createUserRef" :is-create="true" @refresh="search" /> <UserEdit ref="createUserRef" :is-create="true" @refresh="search" />
</a-space> </a-space>
<a-button @click="generateExcel" style="margin-left: 20px"> <a-button style="margin-left: 20px" @click="generateExcel">
<template #icon> <template #icon>
<icon-download size="18" /> <icon-download size="18" />
</template> </template>
@ -168,10 +168,10 @@
:data="renderData" :data="renderData"
:bordered="false" :bordered="false"
:size="size" :size="size"
@page-change="onPageChange"
style="margin-bottom: 40px" style="margin-bottom: 40px"
:filter-icon-align-left="alignLeft" :filter-icon-align-left="alignLeft"
@change="handleSortChange" @change="handleSortChange"
@page-change="onPageChange"
> >
<template #index="{ rowIndex }"> <template #index="{ rowIndex }">
{{ rowIndex + 1 + (pagination.current - 1) * pagination.size }} {{ rowIndex + 1 + (pagination.current - 1) * pagination.size }}
@ -211,12 +211,12 @@
<a-pagination <a-pagination
style="float: right; position: relative; right: 1px; bottom: 25px" style="float: right; position: relative; right: 1px; bottom: 25px"
:total="pagination.total" :total="pagination.total"
@page-size-change="onSizeChange"
:size="size" :size="size"
@change="onPageChange"
show-total show-total
show-jumper show-jumper
show-page-size show-page-size
@page-size-change="onSizeChange"
@change="onPageChange"
/> />
</a-card> </a-card>
</div> </div>
@ -236,9 +236,6 @@ import { downloadExcel, DownloadExcelPrams } from '@/utils/excel';
import useTableOption from '@/hooks/table-option'; import useTableOption from '@/hooks/table-option';
import UserEdit from './components/user-edit.vue'; import UserEdit from './components/user-edit.vue';
type SizeProps = 'mini' | 'small' | 'medium' | 'large';
type Column = TableColumnData & { checked?: true };
const generateFormModel = () => { const generateFormModel = () => {
return { return {
id: '', id: '',
@ -404,9 +401,7 @@ const reset = () => {
// //
const alignLeft = ref(false); const alignLeft = ref(false);
const handleSortChange = (data: any, extra: any, currentDataSource: any) => { const handleSortChange = (data: any, extra: any, currentDataSource: any) => {};
console.log('change', data, extra, currentDataSource);
};
// //
const enabledStatus = async (record: string) => { const enabledStatus = async (record: string) => {

View File

@ -24,20 +24,33 @@
<template #icon><icon-edit /></template> <template #icon><icon-edit /></template>
{{ modalTitle }} {{ modalTitle }}
</a-button> </a-button>
<a-modal <a-modal
width="700px" width="800px"
:visible="visible" :visible="visible"
:footer="false" :footer="false"
@cancel="handleCancel" @cancel="handleCancel"
> >
<template #title>{{ modalTitle }}</template> <template #title>{{ modalTitle }}</template>
<a-form ref="createEditRef" :model="formData" :style="{ width: '650px' }"> <a-form
ref="createEditRef"
:label-col-props="{ span: 6 }"
:wrapper-col-props="{ span: 15 }"
label-align="right"
:model="formData"
:style="{ width: '750px' }"
>
<a-row>
<a-col :span="12">
<a-form-item <a-form-item
field="companyName" field="companyName"
:label="$t('ticket.info.companyName')" :label="$t('ticket.info.companyName')"
:validate-trigger="['change', 'input']" :validate-trigger="['change', 'input']"
:rules="[ :rules="[
{ required: true, message: t('ticket.info.companyName.required') }, {
required: true,
message: t('ticket.info.companyName.required'),
},
]" ]"
style="line-height: 18px" style="line-height: 18px"
> >
@ -46,37 +59,52 @@
:placeholder="$t('ticket.info.companyName.placeholder')" :placeholder="$t('ticket.info.companyName.placeholder')"
/> />
</a-form-item> </a-form-item>
</a-col>
<a-col :span="12">
<a-form-item <a-form-item
field="title" field="title"
:label="$t('ticket.info.title')" :label="$t('ticket.info.title')"
:validate-trigger="['change', 'input']" :validate-trigger="['change', 'input']"
:rules="[{ required: true, message: t('ticket.info.title.required') }]" :rules="[
{ required: true, message: t('ticket.info.title.required') },
]"
> >
<a-input <a-input
v-model="formData.title" v-model="formData.title"
:placeholder="$t('ticket.info.title.placeholder')" :placeholder="$t('ticket.info.title.placeholder')"
/> />
</a-form-item> </a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :span="12">
<a-form-item <a-form-item
field="money" field="money"
:label="$t('ticket.info.money')" :label="$t('ticket.info.money')"
:validate-trigger="['change', 'input']" :validate-trigger="['change', 'input']"
:rules="[{ required: true, message: t('ticket.info.money.required') }]" :rules="[
{ required: true, message: t('ticket.info.money.required') },
]"
> >
<a-input <a-input
v-model="formData.money" v-model="formData.money"
:placeholder="$t('ticket.info.money.placeholder')" :placeholder="$t('ticket.info.money.placeholder')"
/> />
</a-form-item> </a-form-item>
</a-col>
<a-col :span="12">
<a-form-item <a-form-item
field="contactEmail" field="contactEmail"
:label="$t('ticket.info.contactEmail')" :label="$t('ticket.info.contactEmail')"
:validate-trigger="['change', 'input']" :validate-trigger="['change', 'input']"
:rules="[ :rules="[
{ required: true, message: t('ticket.info.contactEmail.required') }, {
required: true,
message: t('ticket.info.contactEmail.required'),
},
]" ]"
> >
<a-input <a-input
@ -84,12 +112,18 @@
:placeholder="$t('ticket.info.contactEmail.placeholder')" :placeholder="$t('ticket.info.contactEmail.placeholder')"
/> />
</a-form-item> </a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :span="12">
<a-form-item <a-form-item
field="type" field="type"
:label="$t('ticket.info.type')" :label="$t('ticket.info.type')"
:validate-trigger="['change', 'input']" :validate-trigger="['change', 'input']"
:rules="[{ required: true, message: t('ticket.info.type.required') }]" :rules="[
{ required: true, message: t('ticket.info.type.required') },
]"
> >
<a-select <a-select
v-model="formData.type" v-model="formData.type"
@ -97,11 +131,15 @@
:placeholder="$t('ticket.info.type.placeholder')" :placeholder="$t('ticket.info.type.placeholder')"
/> />
</a-form-item> </a-form-item>
</a-col>
<a-col :span="12">
<a-form-item <a-form-item
field="deptId" field="deptId"
:label="$t('ticket.info.dept')" :label="$t('ticket.info.dept')"
:rules="[{ required: true, message: t('ticket.info.dept.required') }]" :rules="[
{ required: true, message: t('ticket.info.dept.required') },
]"
:validate-trigger="['change']" :validate-trigger="['change']"
> >
<a-tree-select <a-tree-select
@ -116,7 +154,12 @@
@change="optionDept(true)" @change="optionDept(true)"
/> />
</a-form-item> </a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :span="12">
<a-row>
<a-form-item <a-form-item
field="auditorId" field="auditorId"
:label="$t('ticket.info.auditor')" :label="$t('ticket.info.auditor')"
@ -134,7 +177,8 @@
</div> </div>
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-row>
<a-row>
<a-form-item <a-form-item
field="comment" field="comment"
:label="$t('ticket.info.comment')" :label="$t('ticket.info.comment')"
@ -142,21 +186,31 @@
> >
{{ formData.comment }} {{ formData.comment }}
</a-form-item> </a-form-item>
</a-row>
<a-row>
<a-form-item <a-form-item
field="body" field="body"
:label="$t('ticket.info.body')" :label="$t('ticket.info.body')"
:validate-trigger="['change', 'input']" :validate-trigger="['change', 'input']"
:rules="[{ required: true, message: t('ticket.info.body.required') }]" :rules="[
{ required: true, message: t('ticket.info.body.required') },
]"
> >
<a-textarea <a-textarea
v-model="formData.body" v-model="formData.body"
:placeholder="$t('ticket.info.body.placeholder')" :placeholder="$t('ticket.info.body.placeholder')"
style="height: 100px" style="height: 150px"
/> />
</a-form-item> </a-form-item>
</a-row>
</a-col>
<a-form-item field="attachment" :label="$t('ticket.info.attachment')"> <a-col :span="12"
><a-form-item
field="attachment"
:label="$t('ticket.info.attachment')"
>
<a-upload <a-upload
:file-list="fileList" :file-list="fileList"
:custom-request="Onchange" :custom-request="Onchange"
@ -164,9 +218,11 @@
:on-before-remove="removeAttact" :on-before-remove="removeAttact"
/> />
</a-form-item> </a-form-item>
</a-col>
</a-row>
<a-form-item> <a-form-item style="display: flex; justify-content: center">
<a-button type="dashed" @click="handleCancel"> <a-button type="dashed" style="margin-left: 30px" @click="handleCancel">
{{ $t('cancel') }}</a-button {{ $t('cancel') }}</a-button
> >
<a-button <a-button
@ -296,10 +352,8 @@ const Onchange = async (option: any) => {
}); });
res.data.name = res.data.fileName; res.data.name = res.data.fileName;
fileList.value.push(res.data); fileList.value.push(res.data);
console.log('res', res.data.id);
attachList.value.push(res.data.id); attachList.value.push(res.data.id);
formData.value.attachId = attachList; formData.value.attachId = attachList;
console.log('poti', formData.value.attachId);
} else { } else {
Message.error({ Message.error({
content: t('upload.fail'), content: t('upload.fail'),
@ -310,12 +364,9 @@ const Onchange = async (option: any) => {
// //
const removeAttact = (fileItem: FileItem) => { const removeAttact = (fileItem: FileItem) => {
console.log('2', fileItem.id, fileList.value, attachList.value);
fileList.value = fileList.value.filter((item) => item.id !== fileItem.id); fileList.value = fileList.value.filter((item) => item.id !== fileItem.id);
attachList.value = attachList.value.filter((item) => item !== fileItem.id); attachList.value = attachList.value.filter((item) => item !== fileItem.id);
console.log('3', fileList.value, attachList.value);
formData.value.attachId = attachList.value; formData.value.attachId = attachList.value;
console.log('3', formData.value.attachId);
}; };
// //
@ -332,7 +383,6 @@ const handleClick = () => {
formData.value = res.data; formData.value = res.data;
formData.value.attachId.forEach(async (item: any) => { formData.value.attachId.forEach(async (item: any) => {
console.log('item,', item);
const data = await ticketStore.getAttachment(item); const data = await ticketStore.getAttachment(item);
data.data.name = data.data.fileName; data.data.name = data.data.fileName;
fileList.value.push(data.data); fileList.value.push(data.data);

View File

@ -1,8 +1,8 @@
<template> <template>
<!-- 详情 --> <!-- 详情 -->
<a-button <a-button
v-permission="['BILL_QUERY']"
v-if="props.isDetail" v-if="props.isDetail"
v-permission="['BILL_QUERY']"
type="outline" type="outline"
size="small" size="small"
:style="{ marginRight: '10px', padding: '7px', border: '0px' }" :style="{ marginRight: '10px', padding: '7px', border: '0px' }"
@ -14,8 +14,8 @@
<!-- 审核 --> <!-- 审核 -->
<a-button <a-button
v-permission="['BILL_AUDIT']"
v-if="!props.isDetail" v-if="!props.isDetail"
v-permission="['BILL_AUDIT']"
type="outline" type="outline"
size="small" size="small"
:style="{ marginRight: '10px', padding: '7px', border: '0px' }" :style="{ marginRight: '10px', padding: '7px', border: '0px' }"
@ -178,11 +178,14 @@
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<a-form-item <a-form-item
v-if="!props.isDetail"
field="comment" field="comment"
:label="$t('ticket.info.comment')" :label="$t('ticket.info.comment')"
v-if="!props.isDetail"
> >
<a-textarea v-model="formData.comment" style="height: 200px" /> <a-textarea
v-model="formData.comment"
style="height: 200px; background-color: white; border: 1px solid"
/>
</a-form-item> </a-form-item>
</div> </div>
@ -193,14 +196,14 @@
style="margin-left: -110px" style="margin-left: -110px"
> >
<a-upload <a-upload
v-if="fileList.length !== 0"
v-model="formData.attachId"
:file-list="fileList" :file-list="fileList"
:custom-request="Onchange" :custom-request="Onchange"
:limit="5" :limit="5"
:disabled="true" :disabled="true"
:on-before-remove="removeAttact" :on-before-remove="removeAttact"
:show-remove-button="false" :show-remove-button="false"
v-model="formData.attachId"
v-if="fileList.length !== 0"
/> />
<div v-else></div> <div v-else></div>
</a-form-item> </a-form-item>
@ -214,8 +217,7 @@ import { useI18n } from 'vue-i18n';
import useVisible from '@/hooks/visible'; import useVisible from '@/hooks/visible';
import { computed, PropType, ref } from 'vue'; import { computed, PropType, ref } from 'vue';
import { FormInstance } from '@arco-design/web-vue/es/form'; import { FormInstance } from '@arco-design/web-vue/es/form';
import { SelectOptionData } from '@arco-design/web-vue/es/select/interface'; import { Message } from '@arco-design/web-vue';
import { Button, Message } from '@arco-design/web-vue';
import { useTicketStore, useUserStore, useRoleStore } from '@/store'; import { useTicketStore, useUserStore, useRoleStore } from '@/store';
import { TicketRecord } from '@/api/ticket'; import { TicketRecord } from '@/api/ticket';
import { deptList } from '@/api/dept'; import { deptList } from '@/api/dept';
@ -299,9 +301,9 @@ const handleClick = async () => {
// //
formData.value = res.data; formData.value = res.data;
formData.value.submit = 'true'; formData.value.submit = 'true';
// //
formData.value.attachId.forEach(async (item: any) => { formData.value.attachId.forEach(async (item: any) => {
// console.log('item,', item);
const data = await ticketStore.getAttachment(item); const data = await ticketStore.getAttachment(item);
data.data.name = data.data.fileName; data.data.name = data.data.fileName;
fileList.value.push(data.data); fileList.value.push(data.data);

View File

@ -2,15 +2,19 @@
<div class="container"> <div class="container">
<Breadcrumb :items="['menu.ticket', 'menu.ticket.manage']" /> <Breadcrumb :items="['menu.ticket', 'menu.ticket.manage']" />
<a-card class="general-card"> <a-card class="general-card">
<a-tabs default-active-key="" @change="changeTop"> <a-tabs
<a-tab-pane key="" :title="t('set')"> </a-tab-pane> default-active-key="ALL"
<a-tab-pane key="PASS" :title="t('pass')"> </a-tab-pane> :active-key="tabKey"
@tab-click="changeTop"
>
<a-tab-pane key="ALL" :title="t('set')"> </a-tab-pane>
<a-tab-pane key="FAILED" :title="t('failed')"> </a-tab-pane> <a-tab-pane key="FAILED" :title="t('failed')"> </a-tab-pane>
<a-tab-pane key="PASS" :title="t('pass')"> </a-tab-pane>
<a-tab-pane key="EXAMINE" :title="t('unreviewed')"> </a-tab-pane> <a-tab-pane key="EXAMINE" :title="t('unreviewed')"> </a-tab-pane>
<a-tab-pane <a-tab-pane
v-if="userStore.permissions !== 'auditor'"
key="SUBMIT" key="SUBMIT"
:title="t('drafts')" :title="t('drafts')"
v-if="userStore.permissions !== 'auditor'"
> >
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
@ -103,9 +107,9 @@
v-model="formModel.time" v-model="formModel.time"
style="width: 360px" style="width: 360px"
show-time show-time
@select="onSelect"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
:allow-clear="false" :allow-clear="false"
@select="onSelect"
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
@ -143,7 +147,7 @@
@refresh="search" @refresh="search"
/> />
</a-space> </a-space>
<a-button @click="generateExcel" style="margin-left: 5px"> <a-button style="margin-left: 5px" @click="generateExcel">
<template #icon> <template #icon>
<icon-download size="16" /> <icon-download size="16" />
</template> </template>
@ -220,12 +224,12 @@
:pagination="false" :pagination="false"
:size="size" :size="size"
:expandable="expandable" :expandable="expandable"
@page-change="onPageChange"
style="margin-bottom: 40px" style="margin-bottom: 40px"
@page-change="onPageChange"
> >
<template #expand-row="{ record }"> <template #expand-row="{ record }">
<!-- 下面展示子表格,根据需求对子table进行属性配置 --> <!-- 下面展示子表格,根据需求对子table进行属性配置 -->
<a-descriptions layout="inline-horizontal" :column="1" bordered> <a-descriptions layout="inline-horizontal" :column="1">
<descriptions-item :label="t('ticket.info.contactEmail')"> <descriptions-item :label="t('ticket.info.contactEmail')">
{{ record.contactEmail }} {{ record.contactEmail }}
</descriptions-item> </descriptions-item>
@ -242,16 +246,16 @@
</template> </template>
<template #status="{ record }"> <template #status="{ record }">
<a-button status="success" v-if="record.status === '审核通过'">{{ <a-button v-if="record.status === '审核通过'" status="success">{{
record.status record.status
}}</a-button> }}</a-button>
<a-button status="danger" v-if="record.status === '审核未通过'">{{ <a-button v-if="record.status === '审核未通过'" status="danger">{{
record.status record.status
}}</a-button> }}</a-button>
<a-button status="normal" v-if="record.status === '待审核'">{{ <a-button v-if="record.status === '待审核'" status="normal">{{
record.status record.status
}}</a-button> }}</a-button>
<a-button status="warning" v-if="record.status === '待提交'">{{ <a-button v-if="record.status === '待提交'" status="warning">{{
record.status record.status
}}</a-button> }}</a-button>
</template> </template>
@ -267,20 +271,20 @@
<!-- 修改 --> <!-- 修改 -->
<TicketForm <TicketForm
v-if="record.status === '待提交' || record.status === '审核未通过'"
ref="createEditRef" ref="createEditRef"
:prem="record" :prem="record"
:is-create="false" :is-create="false"
@refresh="search" @refresh="search"
v-if="record.status === '待提交' || record.status === '审核未通过'"
/> />
<!-- 审核 --> <!-- 审核 -->
<TicketEdit <TicketEdit
v-if="record.status === '待审核'"
ref="editRef" ref="editRef"
:prem="record" :prem="record"
:is-detail="false" :is-detail="false"
@refresh="search" @refresh="search"
v-if="record.status === '待审核'"
/> />
<a-popconfirm <a-popconfirm
@ -288,12 +292,12 @@
@ok="handleDelete(record)" @ok="handleDelete(record)"
> >
<a-button <a-button
type="outline"
size="small"
v-permission="['BILL_DELETE']"
v-if=" v-if="
record.status === '待提交' || record.status === '审核未通过' record.status === '待提交' || record.status === '审核未通过'
" "
v-permission="['BILL_DELETE']"
type="outline"
size="small"
style="padding: 7px; border: 0px" style="padding: 7px; border: 0px"
> >
<template #icon><icon-delete /></template> <template #icon><icon-delete /></template>
@ -305,19 +309,19 @@
<a-pagination <a-pagination
style="float: right; position: relative; right: 1px; bottom: 25px" style="float: right; position: relative; right: 1px; bottom: 25px"
:total="pagination.total" :total="pagination.total"
@page-size-change="onSizeChange"
:size="size" :size="size"
@change="onPageChange"
show-total show-total
show-jumper show-jumper
show-page-size show-page-size
@page-size-change="onSizeChange"
@change="onPageChange"
/> />
</a-card> </a-card>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue'; import { computed, reactive, ref, watch, onMounted } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import useLoading from '@/hooks/loading'; import useLoading from '@/hooks/loading';
import useTableOption from '@/hooks/table-option'; import useTableOption from '@/hooks/table-option';
@ -329,6 +333,7 @@ import { Message } from '@arco-design/web-vue';
import { useTicketStore, useUserStore } from '@/store'; import { useTicketStore, useUserStore } from '@/store';
import { TicketRecord } from '@/api/ticket'; import { TicketRecord } from '@/api/ticket';
import { downloadExcel, DownloadExcelPrams } from '@/utils/excel'; import { downloadExcel, DownloadExcelPrams } from '@/utils/excel';
import { useRoute } from 'vue-router';
import TicketEdit from './components/ticket-edit.vue'; import TicketEdit from './components/ticket-edit.vue';
import TicketForm from './components/form-edit.vue'; import TicketForm from './components/form-edit.vue';
@ -352,7 +357,7 @@ const generateFormModel = () => {
companyName: '', companyName: '',
title: '', title: '',
type: '', type: '',
// //
status: '', status: '',
time: [], time: [],
userName: '', userName: '',
@ -368,6 +373,12 @@ const renderData = ref<TicketRecord[]>([]);
const formModel = ref(generateFormModel()); const formModel = ref(generateFormModel());
const currentStatus = ref('PASS'); const currentStatus = ref('PASS');
//
onMounted(() => {
const router = useRoute();
changeTop(router.query.status);
});
// //
const expandable = reactive({ const expandable = reactive({
title: ' ', title: ' ',
@ -481,12 +492,6 @@ const onSelect = (dateString: any, date: any) => {
formModel.value.endTime = String(dateString[1]); formModel.value.endTime = String(dateString[1]);
}; };
//
const onChange = (dateString: any, date: any) => {
formModel.value.startTime = String(dateString[0]);
formModel.value.endTime = String(dateString[1]);
};
// //
const onPageChange = (current: number) => { const onPageChange = (current: number) => {
pagination.page = current; pagination.page = current;
@ -534,26 +539,31 @@ const fetchData = async (params: {
} }
}; };
const tabKey = ref('ALL');
// //
const search = () => { const search = () => {
// time // time
const { time, ...auditDate } = formModel.value; const { time, ...auditDate } = formModel.value;
changeTop('ALL');
};
//
const changeTop = (key: any) => {
tabKey.value = key;
if (tabKey.value === 'ALL') {
formModel.value.status = '';
} else {
formModel.value.status = key;
}
currentStatus.value = key;
const { time, ...auditDate } = formModel.value;
fetchData({ fetchData({
...pagination, ...pagination,
...auditDate, ...auditDate,
} as unknown as any); } as unknown as any);
}; };
//
const changeTop = (key: any) => {
formModel.value.status = key;
currentStatus.value = key;
search();
};
search();
// //
const reset = () => { const reset = () => {
formModel.value = generateFormModel(); formModel.value = generateFormModel();

View File

@ -48,7 +48,7 @@ export default {
'tax': '税务支票', 'tax': '税务支票',
'other': '其他支票', 'other': '其他支票',
'set':'票据集合', 'set':'所有票据',
'unsubmitted': '待提交', 'unsubmitted': '待提交',
'unreviewed': '待审核', 'unreviewed': '待审核',
'pass': '审核通过', 'pass': '审核通过',

View File

@ -3,7 +3,7 @@
ref="formRef" ref="formRef"
:model="formData" :model="formData"
class="form" class="form"
:label-col-props="{ span: 8 }" :label-col-props="{ span: 5 }"
:wrapper-col-props="{ span: 16 }" :wrapper-col-props="{ span: 16 }"
> >
<a-form-item <a-form-item

View File

@ -3,24 +3,9 @@
ref="formRef" ref="formRef"
:model="formData" :model="formData"
class="form" class="form"
:label-col-props="{ span: 8 }" :label-col-props="{ span: 5 }"
:wrapper-col-props="{ span: 16 }" :wrapper-col-props="{ span: 16 }"
> >
<!-- <a-form-item
field="oldPassword"
:label="$t('userSetting.passwordReset.form.label.oldPassword')"
:rules="[{ required: true, message: $t('login.form.password.errMsg') }]"
>
<a-input-password
v-model="formData.oldPassword"
:placeholder="
$t('userSetting.passwordReset.form.label.oldPassword.placeholder')
"
allow-clear
>
</a-input-password>
</a-form-item> -->
<a-form-item <a-form-item
field="password" field="password"
:label="$t('userSetting.passwordReset.form.label.newPassword')" :label="$t('userSetting.passwordReset.form.label.newPassword')"
@ -98,9 +83,6 @@ const user = useUser();
const validate = async () => { const validate = async () => {
const vali = await formRef.value?.validate(); const vali = await formRef.value?.validate();
if (!vali) { if (!vali) {
// do some thing
// you also can use html-type to submit
const res = await resetPassword(formData.value); const res = await resetPassword(formData.value);
if (res.status === 200) { if (res.status === 200) {
Message.success({ Message.success({

View File

@ -48,12 +48,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { ref } from 'vue'; import { ref } from 'vue';
import type { import type { FileItem } from '@arco-design/web-vue/es/upload/interfaces';
FileItem,
RequestOption,
} from '@arco-design/web-vue/es/upload/interfaces';
import { useUserStore, useTicketStore } from '@/store'; import { useUserStore, useTicketStore } from '@/store';
import { userUploadApi } from '@/api/user-center';
import userIcon from '@/assets/images/user-circle.png'; import userIcon from '@/assets/images/user-circle.png';
import type { DescData } from '@arco-design/web-vue/es/descriptions/interface'; import type { DescData } from '@arco-design/web-vue/es/descriptions/interface';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@ -101,7 +97,7 @@ const Onchange = async (option: any) => {
}); });
res.data.name = res.data.fileName; res.data.name = res.data.fileName;
fileList.value.push(res.data); fileList.value.push(res.data);
const data = await selfUpdate({ avatar: res.data.id }); await selfUpdate({ avatar: res.data.id });
await userStore.info(); await userStore.info();
} else { } else {
Message.error({ Message.error({
@ -110,43 +106,6 @@ const Onchange = async (option: any) => {
}); });
} }
}; };
// const customRequest = (options: RequestOption) => {
// // docs: https://axios-http.com/docs/cancellation
// const controller = new AbortController();
// (async function requestWrap() {
// const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options;
// onProgress(20);
// const formData = new FormData();
// formData.append(name as string, fileItem.file as Blob);
// const onUploadProgress = (event: ProgressEvent) => {
// let percent;
// if (event.total > 0) {
// percent = (event.loaded / event.total) * 100;
// }
// onProgress(parseInt(String(percent), 10), event);
// };
// try {
// // https://github.com/axios/axios/issues/1630
// // https://github.com/nuysoft/Mock/issues/127
// const res = await userUploadApi(formData, {
// controller,
// onUploadProgress,
// });
// onSuccess(res);
// } catch (error) {
// onError(error);
// }
// })();
// return {
// abort() {
// controller.abort();
// },
// };
// };
</script> </script>
<style scoped lang="less"> <style scoped lang="less">