Merge branch 'developer'

This commit is contained in:
吴红兵
2026-03-09 15:28:46 +08:00
33 changed files with 619 additions and 735 deletions

140
auto-imports.d.ts vendored
View File

@@ -1,73 +1,73 @@
// Generated by 'unplugin-auto-import'
export {}
export {};
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const createPinia: typeof import('pinia')['createPinia']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineStore: typeof import('pinia')['defineStore']
const effectScope: typeof import('vue')['effectScope']
const getActivePinia: typeof import('pinia')['getActivePinia']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const mapActions: typeof import('pinia')['mapActions']
const mapGetters: typeof import('pinia')['mapGetters']
const mapState: typeof import('pinia')['mapState']
const mapStores: typeof import('pinia')['mapStores']
const mapWritableState: typeof import('pinia')['mapWritableState']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveDirective: typeof import('vue')['resolveDirective']
const setActivePinia: typeof import('pinia')['setActivePinia']
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const storeToRefs: typeof import('pinia')['storeToRefs']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useLink: typeof import('vue-router')['useLink']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
const EffectScope: typeof import('vue')['EffectScope'];
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'];
const computed: typeof import('vue')['computed'];
const createApp: typeof import('vue')['createApp'];
const createPinia: typeof import('pinia')['createPinia'];
const customRef: typeof import('vue')['customRef'];
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'];
const defineComponent: typeof import('vue')['defineComponent'];
const defineStore: typeof import('pinia')['defineStore'];
const effectScope: typeof import('vue')['effectScope'];
const getActivePinia: typeof import('pinia')['getActivePinia'];
const getCurrentInstance: typeof import('vue')['getCurrentInstance'];
const getCurrentScope: typeof import('vue')['getCurrentScope'];
const h: typeof import('vue')['h'];
const inject: typeof import('vue')['inject'];
const isProxy: typeof import('vue')['isProxy'];
const isReactive: typeof import('vue')['isReactive'];
const isReadonly: typeof import('vue')['isReadonly'];
const isRef: typeof import('vue')['isRef'];
const mapActions: typeof import('pinia')['mapActions'];
const mapGetters: typeof import('pinia')['mapGetters'];
const mapState: typeof import('pinia')['mapState'];
const mapStores: typeof import('pinia')['mapStores'];
const mapWritableState: typeof import('pinia')['mapWritableState'];
const markRaw: typeof import('vue')['markRaw'];
const nextTick: typeof import('vue')['nextTick'];
const onActivated: typeof import('vue')['onActivated'];
const onBeforeMount: typeof import('vue')['onBeforeMount'];
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'];
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'];
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'];
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'];
const onDeactivated: typeof import('vue')['onDeactivated'];
const onErrorCaptured: typeof import('vue')['onErrorCaptured'];
const onMounted: typeof import('vue')['onMounted'];
const onRenderTracked: typeof import('vue')['onRenderTracked'];
const onRenderTriggered: typeof import('vue')['onRenderTriggered'];
const onScopeDispose: typeof import('vue')['onScopeDispose'];
const onServerPrefetch: typeof import('vue')['onServerPrefetch'];
const onUnmounted: typeof import('vue')['onUnmounted'];
const onUpdated: typeof import('vue')['onUpdated'];
const provide: typeof import('vue')['provide'];
const reactive: typeof import('vue')['reactive'];
const readonly: typeof import('vue')['readonly'];
const ref: typeof import('vue')['ref'];
const resolveComponent: typeof import('vue')['resolveComponent'];
const resolveDirective: typeof import('vue')['resolveDirective'];
const setActivePinia: typeof import('pinia')['setActivePinia'];
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix'];
const shallowReactive: typeof import('vue')['shallowReactive'];
const shallowReadonly: typeof import('vue')['shallowReadonly'];
const shallowRef: typeof import('vue')['shallowRef'];
const storeToRefs: typeof import('pinia')['storeToRefs'];
const toRaw: typeof import('vue')['toRaw'];
const toRef: typeof import('vue')['toRef'];
const toRefs: typeof import('vue')['toRefs'];
const triggerRef: typeof import('vue')['triggerRef'];
const unref: typeof import('vue')['unref'];
const useAttrs: typeof import('vue')['useAttrs'];
const useCssModule: typeof import('vue')['useCssModule'];
const useCssVars: typeof import('vue')['useCssVars'];
const useLink: typeof import('vue-router')['useLink'];
const useRoute: typeof import('vue-router')['useRoute'];
const useRouter: typeof import('vue-router')['useRouter'];
const useSlots: typeof import('vue')['useSlots'];
const watch: typeof import('vue')['watch'];
const watchEffect: typeof import('vue')['watchEffect'];
const watchPostEffect: typeof import('vue')['watchPostEffect'];
const watchSyncEffect: typeof import('vue')['watchSyncEffect'];
}

View File

@@ -153,3 +153,13 @@ export function getUserListByRole(obj: string) {
method: 'get',
});
}
/**
* 模拟登录(管理员以指定用户身份登录)
*/
export function simulateLogin(userId: string) {
return request({
url: '/auth/token/simulate/' + userId,
method: 'get',
});
}

View File

@@ -69,11 +69,7 @@ export function uploadBidFileNewVersion(data: {
});
}
export function submitBidFileTask(data: {
runJobId: string;
to?: number;
comment?: string;
}) {
export function submitBidFileTask(data: { runJobId: string; to?: number; comment?: string }) {
return request({
url: '/purchase/purchasingbidfile/submit',
method: 'post',
@@ -121,13 +117,7 @@ export function getFlowPurchaseDetail(purchaseId: string) {
});
}
export function tempStoreBidFile(data: {
purchaseId: string;
fileId?: string;
fileName?: string;
fileUrl?: string;
comment?: string;
}) {
export function tempStoreBidFile(data: { purchaseId: string; fileId?: string; fileName?: string; fileUrl?: string; comment?: string }) {
return request({
url: '/purchase/purchasingbidfile/tempStore',
method: 'post',

View File

@@ -31,7 +31,7 @@ const init = () => {
let flowInstId = props.currJob.flowInstId;
let runJobId = props.currJob.id;
src.value = props.currElTab.path + `?token=${token}&tenantId=${tenantId}&flowInstId=${flowInstId}&runJobId=${runJobId}`;
console.log(src.value)
console.log(src.value);
};
function handleJob(jobBtn) {

View File

@@ -95,9 +95,20 @@
<el-switch v-model="scope.row.lockFlag" @change="changeSwitch(scope.row)" active-value="0" inactive-value="9"></el-switch>
</template>
</el-table-column>
<el-table-column :label="$t('common.action')" width="200" fixed="right">
<el-table-column :label="$t('common.action')" width="280" fixed="right">
<template #default="scope">
<div style="display: flex">
<!-- 模拟登录 -->
<el-button
v-auth="'sys_user_simulate'"
icon="User"
text
type="primary"
:disabled="scope.row.username === 'admin'"
@click="handleSimulateLogin(scope.row)"
>
模拟登录
</el-button>
<!-- 重置密码 -->
<popover-input v-model="inputPassword" @confirm="changePassword(scope.row)">
<template #default>
@@ -142,22 +153,31 @@
url="/admin/user/import"
@refreshDataList="getDataList"
/>
<change-role ref="changeRoleRef" />
</div>
</template>
<script lang="ts" name="systemUser" setup>
import { delObj, pageList, putObj } from '/@/api/admin/user';
import { delObj, pageList, putObj, simulateLogin } from '/@/api/admin/user';
import { deptTree } from '/@/api/admin/dept';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';
import { useUserInfo } from '/@/stores/userInfo';
import { Session, Local } from '/@/utils/storage';
import { useRouter } from 'vue-router';
// 动态引入组件
const UserForm = defineAsyncComponent(() => import('./form.vue'));
const QueryTree = defineAsyncComponent(() => import('/@/components/QueryTree/index.vue'));
const PopoverInput = defineAsyncComponent(() => import('/@/components/PopoverInput/index.vue'));
const ChangeRole = defineAsyncComponent(() => import('/@/views/admin/system/role/change-role.vue'));
const { t } = useI18n();
const router = useRouter();
const userStore = useUserInfo();
const changeRoleRef = ref();
// 定义变量内容
const userDialogRef = ref();
@@ -260,4 +280,28 @@ const changePassword = async (row: any) => {
useMessage().success(t('common.optSuccessText'));
getDataList();
};
// 模拟登录
const handleSimulateLogin = async (row: any) => {
try {
await useMessageBox().confirm('确定要以用户 "' + row.realName + '" 的身份登录吗?');
const res = await simulateLogin(row.userId);
if (res.data && res.data.access_token) {
userStore.setTokenCache(res.data.access_token, res.data.refresh_token);
Session.set('userInfo', {
user: { username: res.data.username, userId: res.data.user_id },
});
await userStore.setUserInfos();
useMessage().success('模拟登录成功');
router.push('/');
setTimeout(() => {
changeRoleRef.value?.open();
}, 500);
}
} catch (err: any) {
if (err !== 'cancel') {
useMessage().error(err.msg || '模拟登录失败');
}
}
};
</script>

View File

@@ -20,7 +20,9 @@
<el-descriptions :column="1" border size="small">
<el-descriptions-item label="采购编号">{{ applyData.purchaseNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="项目名称">{{ applyData.projectName || '-' }}</el-descriptions-item>
<el-descriptions-item label="采购金额">{{ applyData.budget ? Number(applyData.budget).toLocaleString() + ' 元' : '-' }}</el-descriptions-item>
<el-descriptions-item label="采购金额">{{
applyData.budget ? Number(applyData.budget).toLocaleString() + ' 元' : '-'
}}</el-descriptions-item>
<el-descriptions-item label="招标代理">{{ applyData.agentName || '-' }}</el-descriptions-item>
<el-descriptions-item label="审批状态">
<el-tag v-if="applyData.fileFlowStatus === '0'" type="primary">运行中</el-tag>
@@ -38,8 +40,8 @@
<span class="card-title">招标文件</span>
</div>
</template>
<el-table :data="docList" border stripe size="small" v-if="docList.length > 0" max-height="300">
<!-- <el-table-column type="index" label="序号" width="50" />-->
<el-table :data="docList" border stripe size="small" v-if="docList.length > 0" max-height="300">
<!-- <el-table-column type="index" label="序号" width="50" />-->
<el-table-column prop="version" label="版本" width="60" align="center">
<template #default="scope">
<el-tag v-if="scope.row.isCurrent === '1'" type="success" size="small">{{ scope.row.version || '-' }}</el-tag>
@@ -151,7 +153,7 @@ const open = async (id: string, row?: any) => {
const docsRes = await getDocList(applyData.value.id);
const docs = docsRes?.data || [];
if (Array.isArray(docs) && docs.length > 0) {
docList.value = docs.map((d: any) => ({
docList.value = docs.map((d: any) => ({
id: d.id || d.fileId,
fileName: d.fileName || d.fileTitle || '招标文件',
fileUrl: d.fileUrl,

View File

@@ -19,11 +19,7 @@
<el-divider content-position="left">采购相关文件补充上传</el-divider>
<el-alert
:type="fileTypeAlertType"
:closable="false"
style="margin-bottom: 16px"
>
<el-alert :type="fileTypeAlertType" :closable="false" style="margin-bottom: 16px">
<template #title>
<span v-if="requiredFileType">{{ requiredFileTypeName }}必传</span>
<span v-else>当前采购方式无需补充材料</span>

View File

@@ -20,7 +20,9 @@
<el-descriptions :column="1" border size="small">
<el-descriptions-item label="采购编号">{{ applyData.purchaseNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="项目名称">{{ applyData.projectName || '-' }}</el-descriptions-item>
<el-descriptions-item label="采购金额">{{ applyData.budget ? Number(applyData.budget).toLocaleString() + ' 元' : '-' }}</el-descriptions-item>
<el-descriptions-item label="采购金额">{{
applyData.budget ? Number(applyData.budget).toLocaleString() + ' 元' : '-'
}}</el-descriptions-item>
<el-descriptions-item label="采购方式">{{ purchaseTypeLabel || '-' }}</el-descriptions-item>
<el-descriptions-item label="补充状态">
<el-tag v-if="applyData.supplementFlowStatus === '1'" type="success">已完成</el-tag>

View File

@@ -11,9 +11,9 @@
</div>
</template>
<div v-loading="loading" style="padding-bottom: 20px">
<!-- <div class="form-toolbar mb12" style="text-align: right">-->
<!-- <el-button type="primary" link icon="QuestionFilled" @click="helpDialogVisible = true"> 帮助 </el-button>-->
<!-- </div>-->
<!-- <div class="form-toolbar mb12" style="text-align: right">-->
<!-- <el-button type="primary" link icon="QuestionFilled" @click="helpDialogVisible = true"> 帮助 </el-button>-->
<!-- </div>-->
<el-form
ref="formRef"
:model="dataForm"
@@ -145,7 +145,7 @@
<upload-file
v-model="dataForm.deptSelfMeetingMinutes"
:limit="1"
:file-type="[ 'pdf', 'jpg', 'jpeg', 'png']"
:file-type="['pdf', 'jpg', 'jpeg', 'png']"
:data="{ fileType: FILE_TYPE_MAP.deptSelfMeetingMinutes }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('deptSelfMeetingMinutes')"
@@ -238,9 +238,9 @@
<upload-file
v-model="dataForm.serviceDirectSelect"
:limit="1"
:file-type="[ 'doc', 'docx']"
:file-type="['doc', 'docx']"
:data="{ fileType: FILE_TYPE_MAP.serviceDirectSelect }"
upload-file-url="/purchase/purchasingfiles/upload"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('serviceDirectSelect')"
/>
<el-button
@@ -266,7 +266,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
<upload-file
v-model="dataForm.serviceInviteSelect"
:limit="1"
:file-type="[ 'doc', 'docx']"
:file-type="['doc', 'docx']"
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('serviceInviteSelect')"
@@ -312,7 +312,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8" class="mb12" v-if="showAutoInviteSelect && dataForm.hasSupplier === '1'">
<el-col :span="8" class="mb12" v-if="showAutoInviteSelect && dataForm.hasSupplier === '1'">
<el-form-item label="服务商城项目需求模板(邀请比选)" prop="serviceInviteSelect" required>
<upload-file
v-model="dataForm.serviceInviteSelect"
@@ -333,7 +333,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
</el-button>
</el-form-item>
</el-col>
<el-col :span="8" class="mb12" v-if="showAutoInviteSelect && dataForm.hasSupplier === '0'">
<el-col :span="8" class="mb12" v-if="showAutoInviteSelect && dataForm.hasSupplier === '0'">
<el-form-item label="服务商城项目需求模板(公开比选)" prop="servicePublicSelectAuto" required>
<upload-file
v-model="dataForm.servicePublicSelectAuto"
@@ -468,7 +468,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
<upload-file
v-model="dataForm.feasibilityReport"
:limit="1"
:file-type="[ 'pdf', 'jpg', 'jpeg', 'png']"
:file-type="['pdf', 'jpg', 'jpeg', 'png']"
:data="{ fileType: FILE_TYPE_MAP.feasibilityReport }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('feasibilityReport')"
@@ -489,7 +489,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
<upload-file
v-model="dataForm.meetingMinutes"
:limit="1"
:file-type="[ 'pdf', 'jpg', 'jpeg', 'png']"
:file-type="['pdf', 'jpg', 'jpeg', 'png']"
:data="{ fileType: FILE_TYPE_MAP.meetingMinutes }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('meetingMinutes')"
@@ -502,7 +502,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
<upload-file
v-model="dataForm.singleSourceProof"
:limit="1"
:file-type="[ 'pdf', 'jpg', 'jpeg', 'png']"
:file-type="['pdf', 'jpg', 'jpeg', 'png']"
:data="{ fileType: FILE_TYPE_MAP.singleSourceProof }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('singleSourceProof')"
@@ -523,7 +523,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
<upload-file
v-model="dataForm.meetingMinutesSingle"
:limit="1"
:file-type="[ 'pdf', 'jpg', 'jpeg', 'png']"
:file-type="['pdf', 'jpg', 'jpeg', 'png']"
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesSingle }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('meetingMinutesSingle')"
@@ -535,7 +535,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
<upload-file
v-model="dataForm.importApplication"
:limit="1"
:file-type="[ 'pdf', 'jpg', 'jpeg', 'png']"
:file-type="['pdf', 'jpg', 'jpeg', 'png']"
:data="{ fileType: FILE_TYPE_MAP.importApplication }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('importApplication')"
@@ -556,7 +556,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
<upload-file
v-model="dataForm.meetingMinutesImport"
:limit="1"
:file-type="[ 'pdf', 'jpg', 'jpeg', 'png']"
:file-type="['pdf', 'jpg', 'jpeg', 'png']"
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesImport }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('meetingMinutesImport')"
@@ -599,7 +599,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
>下载《{{ getTemplateName('invite_select') }}》模版
</el-button>
</template>
<template v-else-if="dataForm.hasSupplier === '0'">
<template v-else-if="dataForm.hasSupplier === '0'">
<upload-file
v-model="dataForm.servicePublicSelectSchoolAuto"
:limit="1"
@@ -619,7 +619,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
</el-button>
</template>
</template>
<template v-else-if="showAutoPublicSelect">
<template v-else-if="showAutoPublicSelect">
<upload-file
v-model="dataForm.servicePublicSelectSchool"
:limit="1"
@@ -638,7 +638,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
>下载《{{ getTemplateName('public_select') }}》模版
</el-button>
</template>
<template v-else>
<template v-else>
<upload-file
v-model="dataForm.purchaseRequirement"
:limit="1"
@@ -664,7 +664,7 @@ upload-file-url="/purchase/purchasingfiles/upload"
<upload-file
v-model="dataForm.governmentPurchaseIntent"
:limit="1"
:file-type="[ 'pdf', 'jpg', 'jpeg', 'png']"
:file-type="['pdf', 'jpg', 'jpeg', 'png']"
:data="{ fileType: FILE_TYPE_MAP.governmentPurchaseIntent }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="flowFieldDisabled('governmentPurchaseIntent')"
@@ -963,7 +963,7 @@ const dataForm = reactive({
isSpecial: '',
hasAssets: '0',
purchaseMode: '',
purchaseSchool:'',
purchaseSchool: '',
purchaseType: '',
purchaseTypeUnion: '',
purchaseChannel: '',
@@ -1577,7 +1577,7 @@ watch(
// 学校统一采购:组织采购形式由规则默认选择,随预算与集采变化自动更新
watch(
[ () => isDeptPurchase.value],
[() => isDeptPurchase.value],
() => {
if (isDeptPurchase.value) return;
},
@@ -1586,37 +1586,16 @@ watch(
// 下载模版:统一走后端接口,按原始文件下载(避免前端静态资源被当成 HTML 返回)
const downloadTemplate = async (type: string) => {
// 优先从后台模版列表获取模版名称
// 从后台模版列表获取模版名称templateName 包含原始文件扩展名)
const backendTemplate = templateList.value.find((t: any) => t.templateType === type);
let displayName = '';
if (backendTemplate?.templateTitle) {
displayName = backendTemplate.templateTitle;
} else {
// 后备:使用本地硬编码的名称
const templateMap: Record<string, string> = {
business_negotiation: '商务洽谈表.doc',
market_purchase_minutes: '部门自行采购市场采购纪要.doc',
inquiry: '部门采购询价模版.doc',
direct_select: '服务商城项目需求模板(直选).doc',
public_select: '服务商城项目需求模板(公开比选).doc',
invite_select: '服务商城项目需求模板(邀请比选).doc',
purchase_requirement: '采购需求填报模板.doc',
import_application: '进口产品申请及专家论证意见表.doc',
single_source: '单一来源论专家证附件.docx',
feasibility_report: '项目可行性论证报告模板.doc',
gov_pur_int: '政府采购意向申请表.doc',
};
displayName = templateMap[type] || '';
}
if (!displayName) {
useMessage().error('模版不存在');
if (!backendTemplate?.templateName) {
useMessage().error('模版不存在或未维护模版文件,请联系管理员');
return;
}
try {
await other.downBlobFile(`/purchase/purchasingtemplate/download?type=${encodeURIComponent(type)}`, {}, displayName);
await other.downBlobFile(`/purchase/purchasingtemplate/download?type=${encodeURIComponent(type)}`, {}, backendTemplate.templateName);
useMessage().success('模版下载成功');
} catch (err) {
useMessage().error('模版下载失败,请联系管理员维护模版文件');

View File

@@ -157,7 +157,7 @@
accept=".doc,.docx"
:disabled="isViewMode"
>
<el-button type="primary" :disabled="isViewMode">选择文件</el-button>
<el-button type="primary" :disabled="isViewMode">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">仅支持 docdocx 格式单文件不超过 50MB上传后自动保存</div>
</template>
@@ -183,7 +183,7 @@
:disabled="isViewMode"
maxlength="500"
show-word-limit
/>
/>
</el-form-item>
</el-form>
</el-card>
@@ -232,13 +232,7 @@
<!-- 指定一人 -->
<el-form-item v-if="representorSelectMode === 'designate'" label="选择参与人">
<el-select
v-model="selectedRepresentor"
placeholder="请选择参与人"
filterable
:disabled="isViewMode"
style="width: 300px"
>
<el-select v-model="selectedRepresentor" placeholder="请选择参与人" filterable :disabled="isViewMode" style="width: 300px">
<el-option
v-for="member in deptMembers"
:key="member.teacherNo"
@@ -278,9 +272,7 @@
<!-- 已选中的参与人 -->
<el-form-item v-if="currentRepresentor" label="已选中参与人">
<el-tag type="success" size="large">
{{ currentRepresentor.realName }} ({{ currentRepresentor.teacherNo }})
</el-tag>
<el-tag type="success" size="large"> {{ currentRepresentor.realName }} ({{ currentRepresentor.teacherNo }}) </el-tag>
</el-form-item>
<!-- 参与人身份 -->
@@ -293,12 +285,7 @@
<!-- 保存按钮 -->
<el-form-item>
<el-button
type="primary"
:loading="saveRepresentorLoading"
:disabled="!canSaveRepresentor || isViewMode"
@click="handleSaveRepresentor"
>
<el-button type="primary" :loading="saveRepresentorLoading" :disabled="!canSaveRepresentor || isViewMode" @click="handleSaveRepresentor">
保存参与人信息
</el-button>
</el-form-item>
@@ -399,7 +386,7 @@ const isFileAudit = computed(() => currentUserRoleCodes.value.includes('PURCHASE
// 是否显示上传区域
const showUploadSection = computed(() => {
if (isViewMode.value) return false;
if (isAgent.value ) return true;
if (isAgent.value) return true;
if (isAsset.value || isDeptApply.value || isFileAudit.value) return true;
return false;
});
@@ -492,7 +479,7 @@ const effectivePurchaseId = computed(() => {
if (props.currJob?.orderId) {
return String(props.currJob.orderId);
}
return route.query.id as string || route.query.purchaseId as string || '';
return (route.query.id as string) || (route.query.purchaseId as string) || '';
});
// 是否可以提交(非查看模式即可提交,不强制要求上传文件)
@@ -630,25 +617,25 @@ const handleDownload = (row: any) => {
};
// 手动保存上传的招标文件
const handleSaveBidFile = async () => {
if (!uploadForm.fileId) {
ElMessage.warning('请先上传招标文件');
return;
}
const handleSaveBidFile = async () => {
if (!uploadForm.fileId) {
ElMessage.warning('请先上传招标文件');
return;
}
saveLoading.value = true;
try {
const saved = await saveUploadedFile();
if (saved) {
ElMessage.success('招标文件保存成功,版本已更新');
}
} finally {
saveLoading.value = false;
saveLoading.value = true;
try {
const saved = await saveUploadedFile();
if (saved) {
ElMessage.success('招标文件保存成功,版本已更新');
}
};
} finally {
saveLoading.value = false;
}
};
// 保存上传的招标文件
const saveUploadedFile = async () => {
// 保存上传的招标文件
const saveUploadedFile = async () => {
if (!uploadForm.fileId) {
ElMessage.warning('请先上传招标文件');
return false;
@@ -724,7 +711,7 @@ const handleFlowSave = async () => {
fileName: uploadForm.fileName || '',
fileUrl: uploadForm.fileUrl || '',
comment: uploadForm.comment || '',
flowTarget: flowTarget.value || ''
flowTarget: flowTarget.value || '',
};
const res = await tempStoreBidFile(params);
@@ -735,8 +722,6 @@ const handleFlowSave = async () => {
currElTabIsSave(props.currJob, props.currElTab.id, true, emit);
}
return true;
} else {
ElMessage.error(res.msg || '暂存失败');
@@ -783,10 +768,7 @@ const handleRandomSelect = async () => {
try {
randomSelectLoading.value = true;
const res = await randomSelectRepresentor(
effectivePurchaseId.value,
randomCandidates.value.join(',')
);
const res = await randomSelectRepresentor(effectivePurchaseId.value, randomCandidates.value.join(','));
if (res.code === 0 && res.data) {
currentRepresentor.value = res.data;
ElMessage.success(`随机抽取成功:${res.data.realName}`);
@@ -816,12 +798,7 @@ const handleSaveRepresentor = async () => {
let res: any;
if (representorSelectMode.value === 'designate') {
res = await saveRepresentor(
Number(effectivePurchaseId.value),
selectedRepresentor.value,
undefined,
representorType.value
);
res = await saveRepresentor(Number(effectivePurchaseId.value), selectedRepresentor.value, undefined, representorType.value);
} else {
res = await saveRepresentor(
Number(effectivePurchaseId.value),

View File

@@ -78,9 +78,9 @@
<el-button type="success" :loading="sendToAgentSubmitting" @click="handleSendToAgent">发送招标代理</el-button>
</el-form-item>
<!-- 撤回招标代理按钮 -->
<!-- <el-form-item v-if="canRevokeAgent">-->
<!-- <el-button type="warning" :loading="revokeAgentSubmitting" @click="handleRevokeAgent">撤回</el-button>-->
<!-- </el-form-item>-->
<!-- <el-form-item v-if="canRevokeAgent">-->
<!-- <el-button type="warning" :loading="revokeAgentSubmitting" @click="handleRevokeAgent">撤回</el-button>-->
<!-- </el-form-item>-->
</div>
</div>
</div>
@@ -287,15 +287,11 @@ const handleSendToAgent = async () => {
// 确认弹窗
try {
await ElMessageBox.confirm(
'是否确认发送至招标代理启动招标文件审核流程?',
'确认发送',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
);
await ElMessageBox.confirm('是否确认发送至招标代理启动招标文件审核流程?', '确认发送', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
});
} catch {
// 用户取消
return;

View File

@@ -5,7 +5,7 @@
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<!-- <el-button type="primary" :loading="confirming" @click="handleConfirm">确定</el-button>-->
<!-- <el-button type="primary" :loading="confirming" @click="handleConfirm">确定</el-button>-->
</div>
</template>
</el-dialog>

View File

@@ -55,7 +55,7 @@
采购申请管理
</span>
<div class="header-actions">
<!-- <el-button icon="QuestionFilled" link type="primary"> 采购申请操作说明文档下载</el-button>-->
<!-- <el-button icon="QuestionFilled" link type="primary"> 采购申请操作说明文档下载</el-button>-->
<el-button icon="FolderAdd" type="primary" @click="handleAdd"> 新增</el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
</div>
@@ -283,10 +283,18 @@
<el-tag v-if="scope.row.fileFlowStatus === '0'" type="primary" class="status-tag-clickable" @click="handleShowDocAudit(scope.row)"
>运行中
</el-tag>
<el-tag v-else-if="scope.row.fileFlowStatus === '1'" type="success" class="status-tag-clickable" @click="handleShowDocAudit(scope.row)"
<el-tag
v-else-if="scope.row.fileFlowStatus === '1'"
type="success"
class="status-tag-clickable"
@click="handleShowDocAudit(scope.row)"
>完成
</el-tag>
<el-tag v-else-if="scope.row.fileFlowStatus === '2'" type="danger" class="status-tag-clickable" @click="handleShowDocAudit(scope.row)"
<el-tag
v-else-if="scope.row.fileFlowStatus === '2'"
type="danger"
class="status-tag-clickable"
@click="handleShowDocAudit(scope.row)"
>作废
</el-tag>
<el-tag v-else-if="scope.row.fileFlowStatus === '3'" type="info" class="status-tag-clickable" @click="handleShowDocAudit(scope.row)"

View File

@@ -29,12 +29,7 @@
</span>
</div>
</template>
<el-alert
v-if="requiredFileTypeName"
type="info"
:closable="false"
style="margin-bottom: 16px"
>
<el-alert v-if="requiredFileTypeName" type="info" :closable="false" style="margin-bottom: 16px">
<template #title>
<span>{{ requiredFileTypeName }}</span>
</template>

View File

@@ -12,7 +12,6 @@
<div class="header-actions">
<el-button icon="Plus" type="primary" @click="formDialogRef.openDialog()"> 新增 </el-button>
<el-button icon="Upload" type="success" class="ml10" @click="handleImport"> 导入 </el-button>
<el-button icon="Download" type="warning" class="ml10" @click="handleExport"> 导出 </el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
<TableColumnControl
ref="columnControlRef"
@@ -108,47 +107,35 @@
<form-dialog ref="formDialogRef" @refresh="getDataList" />
<!-- 导入弹窗 -->
<el-dialog title="导入获奖活动信息" v-model="importDialogVisible" :width="500" :close-on-click-modal="false" draggable>
<div style="margin-bottom: 15px">
<el-button icon="Download" type="success" @click="handleDownloadTemplate"> 下载模板 </el-button>
</div>
<el-upload ref="uploadRef" :auto-upload="false" :on-change="handleFileChange" :limit="1" accept=".xlsx,.xls" drag>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">只能上传 xlsx/xls 文件</div>
</template>
</el-upload>
<template #footer>
<span class="dialog-footer">
<el-button @click="importDialogVisible = false"> </el-button>
<el-button type="primary" @click="handleImportSubmit" :disabled="!importFile || importLoading"> </el-button>
</span>
</template>
</el-dialog>
<upload-excel
ref="uploadExcelRef"
:title="'导入活动获奖'"
:url="'/stuwork/file/importActivityAwards'"
:temp-url="'/stuwork/file/exportActivityAwardsTemplate'"
@refreshDataList="getDataList"
/>
</div>
</template>
<script setup lang="ts" name="ActivityAwards">
import { reactive, ref } from 'vue';
import { reactive, ref, defineAsyncComponent } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj } from '/@/api/stuwork/activityawards';
import { exportActivityAwardsTemplate, importActivityAwards, downloadBlobFile } from '/@/api/stuwork/file';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { parseTime } from '/@/utils/formatTime';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import { UploadFilled, List, Trophy, CreditCard, Avatar, Medal, Calendar, EditPen, Setting, Menu, Document } from '@element-plus/icons-vue';
import { List, Trophy, CreditCard, Avatar, Medal, Calendar, EditPen, Setting, Menu, Document } from '@element-plus/icons-vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
import FormDialog from './form.vue';
// 引入组件
const UploadExcel = defineAsyncComponent(() => import('/@/components/Upload/Excel.vue'));
// 定义变量内容
const formDialogRef = ref();
const uploadRef = ref();
const uploadExcelRef = ref();
const columnControlRef = ref();
const showSearch = ref(false);
const importDialogVisible = ref(false);
const importFile = ref<File | null>(null);
const importLoading = ref(false);
// 表格列配置
const tableColumns = [
@@ -205,47 +192,8 @@ const handleDelete = async (row: any) => {
// 导入
const handleImport = () => {
importDialogVisible.value = true;
importFile.value = null;
uploadRef.value?.clearFiles();
};
// 导出
const handleExport = async () => {
await downloadBlobFile(exportActivityAwardsTemplate(), '活动获奖导入模板.xlsx');
};
// 下载模板
const handleDownloadTemplate = async () => {
await downloadBlobFile(exportActivityAwardsTemplate(), '活动获奖导入模板.xlsx');
};
// 文件变化
const handleFileChange = (file: any) => {
importFile.value = file.raw;
};
// 提交导入
const handleImportSubmit = async () => {
if (!importFile.value) {
useMessage().warning('请选择要导入的文件');
return;
}
importLoading.value = true;
try {
const formData = new FormData();
formData.append('file', importFile.value);
await importActivityAwards(formData);
useMessage().success('导入成功');
importDialogVisible.value = false;
importFile.value = null;
uploadRef.value?.clearFiles();
getDataList();
} catch (err: any) {
useMessage().error(err.msg || '导入失败');
} finally {
importLoading.value = false;
if (uploadExcelRef.value) {
uploadExcelRef.value.show();
}
};
</script>

View File

@@ -131,7 +131,8 @@
<script setup lang="ts" name="ActivityInfoSubSignup">
import { reactive, ref, onMounted, computed } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj, exportExcel, getActivityInfoList, getActivityInfoSubList } from '/@/api/stuwork/activityinfosubsignup';
import { fetchList, delObj, getActivityInfoList, getActivityInfoSubList } from '/@/api/stuwork/activityinfosubsignup';
import { makeExportActivitySignUpDetailTask } from '/@/api/stuwork/file';
import { useMessage, useMessageBox } from '/@/hooks/message';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import {
@@ -246,19 +247,8 @@ const handleDelete = async (row: any) => {
const handleExport = async () => {
exportLoading.value = true;
try {
const res = await exportExcel(state.queryForm);
const blob = new Blob([res.data as BlobPart], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `活动报名表_${new Date().getTime()}.xlsx`;
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(link);
useMessage().success('导出成功');
await makeExportActivitySignUpDetailTask(state.queryForm);
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
} finally {

View File

@@ -271,7 +271,8 @@
<script setup lang="ts" name="ClassFeeLog">
import { reactive, ref, onMounted, computed } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj, exportExcel, getSummary } from '/@/api/stuwork/classfeelog';
import { fetchList, delObj, getSummary } from '/@/api/stuwork/classfeelog';
import { makeExportClassFundTask } from '/@/api/stuwork/file';
import { getDeptList } from '/@/api/basic/basicclass';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getClassListByRole } from '/@/api/basic/basicclass';
@@ -402,20 +403,8 @@ const handleViewAttachment = (row: any) => {
// 导出
const handleExport = async () => {
try {
const res = await exportExcel(state.queryForm);
const blob = new Blob([res], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
const fileName = `班费记录_${new Date().getTime()}.xlsx`;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
useMessage().success('导出成功');
await makeExportClassFundTask(state.queryForm);
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
}

View File

@@ -47,6 +47,7 @@
</span>
<div class="header-actions">
<el-button icon="Download" type="success" @click="handleExport"> 导出 </el-button>
<el-button icon="Download" type="primary" plain @click="handleAsyncExport"> 异步导出 </el-button>
<el-button icon="Refresh" type="primary" class="ml10" @click="handleSync"> 同步教室安排 </el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
<TableColumnControl
@@ -175,6 +176,7 @@
import { reactive, ref, onMounted } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, exportData, syncClassroomArrangement } from '/@/api/stuwork/classroombase';
import { makeExportClassAssetsTask } from '/@/api/stuwork/file';
import { getDeptListByLevelTwo } from '/@/api/basic/basicdept';
import { queryAllClass } from '/@/api/basic/basicclass';
import { getDicts } from '/@/api/admin/dict';
@@ -360,6 +362,16 @@ const handleExport = async () => {
}
};
// 异步导出
const handleAsyncExport = async () => {
try {
await makeExportClassAssetsTask(searchForm);
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
}
};
// 同步教室安排
const handleSync = async () => {
const { confirm } = useMessageBox();

View File

@@ -226,7 +226,8 @@
<script setup lang="ts" name="ClassSafeEdu">
import { reactive, ref, onMounted } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj, exportExcel, statisticsByYearTerm } from '/@/api/stuwork/classsafeedu';
import { fetchList, delObj, statisticsByYearTerm } from '/@/api/stuwork/classsafeedu';
import { makeExportSafetyEducationTask } from '/@/api/stuwork/file';
import { getClassListByRole } from '/@/api/basic/basicclass';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getDicts } from '/@/api/admin/dict';
@@ -346,31 +347,8 @@ const handleViewImage = (url: string) => {
// 导出
const handleExport = async () => {
try {
const res = await exportExcel(state.queryForm);
// 创建blob对象
const blob = new Blob([res], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
// 创建下载链接
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
// 设置文件名
const fileName = `安全教育_${new Date().getTime()}.xlsx`;
link.setAttribute('download', fileName);
// 触发下载
document.body.appendChild(link);
link.click();
// 清理
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
useMessage().success('导出成功');
await makeExportSafetyEducationTask(state.queryForm);
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
}

View File

@@ -48,7 +48,6 @@
</span>
<div class="header-actions">
<el-button icon="Upload" type="primary" @click="handleImport"> 导入 </el-button>
<el-button icon="Download" type="warning" class="ml10" @click="handleExport"> 导出 </el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
</div>
</div>
@@ -162,43 +161,68 @@
</el-dialog>
<!-- 导入对话框 -->
<upload-excel
ref="uploadExcelRef"
:title="'导入宿舍月卫生'"
:url="'/stuwork/file/importDormHygieneMonthly'"
:temp-url="templateUrl"
@refreshDataList="getDataList"
/>
<el-dialog v-model="importDialogVisible" title="导入宿舍月卫生" width="500px" :close-on-click-modal="false">
<el-form :model="importForm" ref="importFormRef" label-width="80px" style="margin-bottom: 15px">
<el-form-item label="楼号" prop="buildingNo">
<el-select v-model="importForm.buildingNo" placeholder="请选择楼号" filterable style="width: 100%">
<el-option v-for="item in buildingList" :key="item.buildingNo" :label="item.buildingNo" :value="item.buildingNo" />
</el-select>
</el-form-item>
<el-form-item label="月份" prop="month">
<el-date-picker
v-model="importForm.month"
type="month"
placeholder="选择月份"
format="YYYY-MM"
value-format="YYYY-MM"
style="width: 100%"
/>
</el-form-item>
<el-form-item>
<el-button icon="Download" type="success" @click="handleDownloadTemplate"> 下载模板 </el-button>
</el-form-item>
</el-form>
<el-upload ref="importUploadRef" :auto-upload="false" :on-change="handleImportFileChange" :limit="1" accept=".xlsx,.xls" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip text-center">只能上传 xlsx/xls 文件请先选择楼号和月份后下载模板</div>
</template>
</el-upload>
<template #footer>
<el-button @click="importDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleImportSubmit" :disabled="!importFile || importLoading">确认导入</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="DormHygieneMonthly">
import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
import { reactive, ref, onMounted } from 'vue';
import { fetchList, addObj, editObj, delObj, triggerEvaluation } from '/@/api/stuwork/dormhygienemonthly';
import { exportDormHygieneMonthlyTemplate, downloadBlobFile } from '/@/api/stuwork/file';
import { exportDormHygieneMonthlyTemplate, importDormHygieneMonthly, downloadBlobFile } from '/@/api/stuwork/file';
import { getBuildingList } from '/@/api/stuwork/dormbuilding';
import { useMessage } from '/@/hooks/message';
import { Search, Document, Plus, Edit, Delete, Promotion } from '@element-plus/icons-vue';
// 引入组件
const UploadExcel = defineAsyncComponent(() => import('/@/components/Upload/Excel.vue'));
// 定义变量内容
const searchFormRef = ref();
const formRef = ref();
const evalFormRef = ref();
const uploadExcelRef = ref();
const importFormRef = ref();
const importUploadRef = ref();
const showSearch = ref(true);
const loading = ref(false);
const submitLoading = ref(false);
const evalLoading = ref(false);
const importLoading = ref(false);
const dataList = ref<any[]>([]);
const buildingList = ref<any[]>([]);
const dialogVisible = ref(false);
const evalDialogVisible = ref(false);
const dialogTitle = ref('新增宿舍月卫生');
// 模板文件URL
const templateUrl = ref('/stuwork/file/exportDormHygieneMonthlyTemplate');
const evalDialogVisible = ref(false);
const importDialogVisible = ref(false);
const importFile = ref<File | null>(null);
// 分页
const page = reactive({
@@ -229,6 +253,12 @@ const evalForm = reactive({
month: '',
});
// 导入表单
const importForm = reactive({
buildingNo: '',
month: '',
});
// 表单校验规则
const rules = {
month: [{ required: true, message: '请选择月份', trigger: 'change' }],
@@ -344,14 +374,55 @@ const handleEvaluation = () => {
// 导入
const handleImport = () => {
if (uploadExcelRef.value) {
uploadExcelRef.value.show();
importForm.buildingNo = '';
importForm.month = '';
importFile.value = null;
importDialogVisible.value = true;
};
// 下载模板
const handleDownloadTemplate = async () => {
if (!importForm.buildingNo) {
useMessage().warning('请先选择楼号');
return;
}
if (!importForm.month) {
useMessage().warning('请先选择月份');
return;
}
try {
await downloadBlobFile(exportDormHygieneMonthlyTemplate(importForm), `宿舍月卫生导入模板_${importForm.month}.xlsx`);
} catch (err: any) {
useMessage().error(err?.msg || '下载模板失败');
}
};
// 导
const handleExport = async () => {
await downloadBlobFile(exportDormHygieneMonthlyTemplate(searchForm), '宿舍月卫生.xlsx');
// 导入文件变化
const handleImportFileChange = (file: any) => {
importFile.value = file.raw;
};
// 提交导入
const handleImportSubmit = async () => {
if (!importFile.value) {
useMessage().warning('请先选择要上传的文件');
return;
}
importLoading.value = true;
try {
const formData = new FormData();
formData.append('file', importFile.value);
await importDormHygieneMonthly(formData);
useMessage().success('导入成功');
importDialogVisible.value = false;
importFile.value = null;
getDataList();
} catch (err: any) {
useMessage().error(err.msg || '导入失败');
} finally {
importLoading.value = false;
}
};
// 提交评比

View File

@@ -187,11 +187,11 @@ import { ref, reactive, defineAsyncComponent, computed, onMounted, nextTick } fr
import { useRoute } from 'vue-router';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, putObj, delObjs } from '/@/api/stuwork/dormreform';
import { makeExportDormReformTask } from '/@/api/stuwork/file';
import { getBuildingList } from '/@/api/stuwork/dormbuilding';
import { getDormRoomDataByBuildingNo } from '/@/api/stuwork/dormroom';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { getDicts } from '/@/api/admin/dict';
import { downBlobFile, adaptationUrl } from '/@/utils/other';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
// 引入组件
@@ -345,8 +345,13 @@ const handleDelete = async (row: any) => {
};
// 导出
const handleExport = () => {
downBlobFile(adaptationUrl('/stuwork/dormreform/export'), searchForm, '月卫生检查整改.xlsx');
const handleExport = async () => {
try {
await makeExportDormReformTask(searchForm);
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
}
};
// 格式化整改结果

View File

@@ -167,10 +167,10 @@ import { ref, reactive, defineAsyncComponent, onMounted, computed, nextTick } fr
import { useRoute } from 'vue-router';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj, editDept } from '/@/api/stuwork/dormroom';
import { makeExportDormRoomTask } from '/@/api/stuwork/file';
import { getDeptList } from '/@/api/basic/basicclass';
import { getBuildingList } from '/@/api/stuwork/dormbuilding';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { downBlobFile, adaptationUrl } from '/@/utils/other';
import { getDicts } from '/@/api/admin/dict';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
@@ -321,8 +321,8 @@ const confirmDeptAssign = async () => {
// 导出
const handleExport = async () => {
try {
await downBlobFile(adaptationUrl('/stuwork/dormroom/export'), searchForm, '宿舍房间.xlsx');
useMessage().success('导出成功');
await makeExportDormRoomTask(searchForm);
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
}

View File

@@ -1,6 +1,10 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 顶部工具栏 -->
<div class="mb10">
<el-button icon="Download" type="primary" plain @click="handleExport"> 导出 </el-button>
</div>
<!-- 表格 -->
<el-table
:data="state.dataList"
@@ -32,6 +36,7 @@
import { reactive, onMounted } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { queryStudentAbnormal } from '/@/api/stuwork/dormroomstudent';
import { makeExportDormStudentAbnormalTask } from '/@/api/stuwork/file';
import { useMessage } from '/@/hooks/message';
// 配置 useTable
@@ -75,6 +80,16 @@ const handleView = (row: any) => {
// TODO: 实现查看详情功能
};
// 导出
const handleExport = async () => {
try {
await makeExportDormStudentAbnormalTask();
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err?.msg || '导出失败');
}
};
// 初始化
onMounted(() => {
getDataList();

View File

@@ -194,7 +194,8 @@
import { reactive, ref, onMounted, computed, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObjs, exportEmptyPeopleRoomExcel } from '/@/api/stuwork/dormroomstudent';
import { fetchList, delObjs } from '/@/api/stuwork/dormroomstudent';
import { makeExportDormStudentTask, makeExportDormStudentAbnormalTask, makeExportDormStatisticsTask } from '/@/api/stuwork/file';
import { getDeptList } from '/@/api/basic/basicclass';
import { getBuildingList } from '/@/api/stuwork/dormbuilding';
import { fetchDormRoomTreeList } from '/@/api/stuwork/dormroom';
@@ -376,24 +377,14 @@ const handleExport = async () => {
stuNo: searchForm.stuNo,
realName: searchForm.realName,
};
const res = await exportEmptyPeopleRoomExcel(params);
const blob =
res instanceof Blob ? res : new Blob([res as BlobPart], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `空宿舍导出_${Date.now()}.xlsx`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
useMessage().success('导出成功');
await makeExportDormStatisticsTask(params);
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err?.msg || '导出失败');
}
};
// 名单导出:与导出共用空 n 人宿舍导出接口,文件名区分
// 名单导出:住宿学生名单导出
const handleExportList = async () => {
try {
const params = {
@@ -406,18 +397,8 @@ const handleExportList = async () => {
stuNo: searchForm.stuNo,
realName: searchForm.realName,
};
const res = await exportEmptyPeopleRoomExcel(params);
const blob =
res instanceof Blob ? res : new Blob([res as BlobPart], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `住宿学生名单_${Date.now()}.xlsx`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
useMessage().success('导出成功');
await makeExportDormStudentTask(params);
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err?.msg || '导出失败');
}

View File

@@ -57,7 +57,6 @@
<div class="header-actions">
<el-button icon="Plus" type="primary" @click="formDialogRef.openDialog()"> 新增 </el-button>
<el-button icon="Upload" type="success" class="ml10" @click="handleImport"> 导入 </el-button>
<el-button icon="Download" type="warning" class="ml10" @click="handleExport"> 导出 </el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
<TableColumnControl
ref="columnControlRef"
@@ -150,60 +149,37 @@
<!-- 新增/编辑表单弹窗 -->
<form-dialog ref="formDialogRef" @refresh="getDataList" />
<!-- 导入弹窗 -->
<el-dialog title="导入文明班级" v-model="importDialogVisible" :width="500" :close-on-click-modal="false" draggable>
<div style="margin-bottom: 15px">
<el-button icon="Download" type="success" @click="handleDownloadTemplate"> 下载模板 </el-button>
</div>
<el-upload ref="uploadRef" :auto-upload="false" :on-change="handleFileChange" :limit="1" accept=".xlsx,.xls" drag>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">只能上传 xlsx/xls 文件</div>
</template>
</el-upload>
<template #footer>
<span class="dialog-footer">
<el-button @click="importDialogVisible = false"> </el-button>
<el-button type="primary" @click="handleImportSubmit" :disabled="!importFile || importLoading"> </el-button>
</span>
</template>
</el-dialog>
<!-- 导入对话框 -->
<upload-excel
ref="uploadExcelRef"
:title="'导入文明班级'"
:url="'/stuwork/file/importRewardClass'"
:temp-url="'/stuwork/file/exportRewardClassTemplate'"
@refreshDataList="getDataList"
/>
</div>
</template>
<script setup lang="ts" name="RewardClass">
import { reactive, ref, onMounted } from 'vue';
import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj } from '/@/api/stuwork/rewardclass';
import { exportRewardClassTemplate, importRewardClass, downloadBlobFile } from '/@/api/stuwork/file';
import { getDeptList } from '/@/api/basic/basicclass';
import { getClassListByRole } from '/@/api/basic/basicclass';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getDicts } from '/@/api/admin/dict';
import { useMessage, useMessageBox } from '/@/hooks/message';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import {
UploadFilled,
List,
Calendar,
Clock,
OfficeBuilding,
Grid,
UserFilled,
Trophy,
EditPen,
Setting,
Menu,
Search,
Document,
} from '@element-plus/icons-vue';
import { List, Calendar, Clock, OfficeBuilding, Grid, UserFilled, Trophy, EditPen, Setting, Menu, Search, Document } from '@element-plus/icons-vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
import FormDialog from './form.vue';
// 引入组件
const UploadExcel = defineAsyncComponent(() => import('/@/components/Upload/Excel.vue'));
// 定义变量内容
const formDialogRef = ref();
const uploadRef = ref();
const uploadExcelRef = ref();
const searchFormRef = ref();
const columnControlRef = ref();
const showSearch = ref(true);
@@ -211,9 +187,6 @@ const schoolYearList = ref<any[]>([]);
const schoolTermList = ref<any[]>([]);
const deptList = ref<any[]>([]);
const classList = ref<any[]>([]);
const importDialogVisible = ref(false);
const importFile = ref<File | null>(null);
const importLoading = ref(false);
// 表格列配置
const tableColumns = [
@@ -280,47 +253,8 @@ const handleReset = () => {
// 导入
const handleImport = () => {
importDialogVisible.value = true;
importFile.value = null;
uploadRef.value?.clearFiles();
};
// 导出
const handleExport = async () => {
await downloadBlobFile(exportRewardClassTemplate(), '文明班级导入模板.xlsx');
};
// 下载模板
const handleDownloadTemplate = async () => {
await downloadBlobFile(exportRewardClassTemplate(), '文明班级导入模板.xlsx');
};
// 文件变化
const handleFileChange = (file: any) => {
importFile.value = file.raw;
};
// 提交导入
const handleImportSubmit = async () => {
if (!importFile.value) {
useMessage().warning('请选择要导入的文件');
return;
}
importLoading.value = true;
try {
const formData = new FormData();
formData.append('file', importFile.value);
await importRewardClass(formData);
useMessage().success('导入成功');
importDialogVisible.value = false;
importFile.value = null;
uploadRef.value?.clearFiles();
getDataList();
} catch (err: any) {
useMessage().error(err.msg || '导入失败');
} finally {
importLoading.value = false;
if (uploadExcelRef.value) {
uploadExcelRef.value.show();
}
};

View File

@@ -46,7 +46,6 @@
<div class="header-actions">
<el-button icon="Plus" type="primary" @click="formDialogRef.openDialog()"> 新增 </el-button>
<el-button icon="Upload" type="success" class="ml10" @click="handleImport"> 导入 </el-button>
<el-button icon="Download" type="warning" class="ml10" @click="handleExport"> 导出 </el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
<TableColumnControl
ref="columnControlRef"
@@ -137,53 +136,41 @@
<form-dialog ref="formDialogRef" @refresh="getDataList" />
<!-- 导入对话框 -->
<el-dialog title="导入数据" v-model="importDialogVisible" :width="500" :close-on-click-modal="false" draggable>
<div style="margin-bottom: 15px">
<el-button icon="Download" type="success" @click="handleDownloadTemplate"> 下载模板 </el-button>
</div>
<el-upload ref="uploadRef" :auto-upload="false" :on-change="handleFileChange" :limit="1" accept=".xlsx,.xls" drag>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">只能上传 xlsx/xls 文件</div>
</template>
</el-upload>
<template #footer>
<span class="dialog-footer">
<el-button @click="importDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleImportSubmit" :disabled="!importFile || importLoading">确认</el-button>
</span>
</template>
</el-dialog>
<upload-excel
ref="uploadExcelRef"
:title="'导入文明宿舍'"
:url="'/stuwork/file/importRewardDorm'"
:temp-url="'/stuwork/file/exportRewardDormTemplate'"
@refreshDataList="getDataList"
/>
</div>
</template>
<script setup lang="ts" name="RewardDorm">
import { reactive, ref, onMounted, computed } from 'vue';
import { reactive, ref, onMounted, computed, defineAsyncComponent } from 'vue';
import { useRoute } from 'vue-router';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj } from '/@/api/stuwork/rewarddorm';
import { exportRewardDormTemplate, importRewardDorm, downloadBlobFile } from '/@/api/stuwork/file';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getDicts } from '/@/api/admin/dict';
import { useMessage, useMessageBox } from '/@/hooks/message';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import { UploadFilled, List, Calendar, Clock, House, Trophy, EditPen, Setting, Menu, Search, Document } from '@element-plus/icons-vue';
import { List, Calendar, Clock, House, Trophy, EditPen, Setting, Menu, Search, Document } from '@element-plus/icons-vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
import FormDialog from './form.vue';
// 引入组件
const UploadExcel = defineAsyncComponent(() => import('/@/components/Upload/Excel.vue'));
// 定义变量
const route = useRoute();
const formDialogRef = ref();
const uploadRef = ref();
const uploadExcelRef = ref();
const searchFormRef = ref();
const columnControlRef = ref();
const showSearch = ref(true);
const schoolYearList = ref<any[]>([]);
const schoolTermList = ref<any[]>([]);
const importDialogVisible = ref(false);
const importFile = ref<File | null>(null);
const importLoading = ref(false);
// 表格列配置
const tableColumns = [
@@ -243,47 +230,8 @@ const handleReset = () => {
// 导入
const handleImport = () => {
importDialogVisible.value = true;
importFile.value = null;
uploadRef.value?.clearFiles();
};
// 导出
const handleExport = async () => {
await downloadBlobFile(exportRewardDormTemplate(), '文明宿舍导入模板.xlsx');
};
// 下载模板
const handleDownloadTemplate = async () => {
await downloadBlobFile(exportRewardDormTemplate(), '文明宿舍导入模板.xlsx');
};
// 文件变化
const handleFileChange = (file: any) => {
importFile.value = file.raw;
};
// 提交导入
const handleImportSubmit = async () => {
if (!importFile.value) {
useMessage().warning('请先选择要上传的文件');
return;
}
importLoading.value = true;
try {
const formData = new FormData();
formData.append('file', importFile.value);
await importRewardDorm(formData);
useMessage().success('导入成功');
importDialogVisible.value = false;
importFile.value = null;
uploadRef.value?.clearFiles();
getDataList();
} catch (err: any) {
useMessage().error(err.msg || '导入失败');
} finally {
importLoading.value = false;
if (uploadExcelRef.value) {
uploadExcelRef.value.show();
}
};

View File

@@ -206,33 +206,19 @@
</template>
<script setup lang="ts" name="RewardStudent">
import { reactive, ref, onMounted, computed, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { fetchList, exportExcel, updateStuAward, getStuRewardList, getRewardRuleList } from '/@/api/stuwork/rewardstudent';
import { getDeptList } from '/@/api/basic/basicclass';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getClassListByRole } from '/@/api/basic/basicclass';
import { getDicts } from '/@/api/admin/dict';
import { useMessage } from '/@/hooks/message';
import { parseTime } from '/@/utils/formatTime';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import {
List,
OfficeBuilding,
Grid,
CreditCard,
Avatar,
DataAnalysis,
Warning,
Trophy,
Clock,
Menu,
Search,
Document,
Setting,
View,
} from '@element-plus/icons-vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
import { reactive, ref, onMounted, computed, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { fetchList, updateStuAward, getStuRewardList, getRewardRuleList } from "/@/api/stuwork/rewardstudent";
import { makeExportStudentPraiseTask } from "/@/api/stuwork/file";
import { getDeptList } from "/@/api/basic/basicclass";
import { queryAllSchoolYear } from "/@/api/basic/basicyear";
import { getClassListByRole } from "/@/api/basic/basicclass";
import { getDicts } from "/@/api/admin/dict";
import { useMessage } from "/@/hooks/message";
import { parseTime } from "/@/utils/formatTime";
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
import { List, OfficeBuilding, Grid, CreditCard, Avatar, DataAnalysis, Warning, Trophy, Clock, Menu, Search, Document, Setting, View } from '@element-plus/icons-vue'
import { useTableColumnControl } from '/@/hooks/tableColumn'
const dateTimeFormat = '{y}-{m}-{d} {h}:{i}:{s}';
@@ -352,38 +338,15 @@ const handleReset = () => {
// 导出
const handleExport = async () => {
try {
loading.value = true;
const res = await exportExcel(queryForm);
// 创建 blob
const blob = new Blob([res], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
// 创建下载链接
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
// 设置文件名
const fileName = `奖励学生_${new Date().getTime()}.xlsx`;
link.setAttribute('download', fileName);
// 触发下载
document.body.appendChild(link);
link.click();
// 清理
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
useMessage().success('导出成功');
loading.value = true
await makeExportStudentPraiseTask(queryForm)
useMessage().success('导出任务已创建,请在文件管理中下载')
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
useMessage().error(err.msg || '导出失败')
} finally {
loading.value = false;
loading.value = false
}
};
}
// 获取学年列表
const getSchoolYearList = async () => {

View File

@@ -64,7 +64,9 @@
</span>
<div class="header-actions">
<el-button icon="Plus" type="primary" @click="formDialogRef.openDialog()"> 新增 </el-button>
<el-button icon="Upload" type="success" class="ml10" @click="handleImport"> 导入 </el-button>
<el-button icon="Upload" type="success" class="ml10" @click="handleImport"> 导入行为记录 </el-button>
<el-button icon="Download" type="primary" plain class="ml10" @click="handleDownloadConductTemplate"> 导入考核模板 </el-button>
<el-button icon="Upload" type="warning" class="ml10" @click="handleConductImport"> 导入考核 </el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
<TableColumnControl
ref="columnControlRef"
@@ -167,7 +169,7 @@
<form-dialog ref="formDialogRef" @refresh="getDataList" />
<!-- 导入对话框 -->
<el-dialog title="导入数据" v-model="importDialogVisible" :width="500" :close-on-click-modal="false" draggable>
<el-dialog title="导入行为记录" v-model="importDialogVisible" :width="500" :close-on-click-modal="false" draggable>
<el-upload ref="uploadRef" :auto-upload="false" :on-change="handleFileChange" :limit="1" accept=".xlsx,.xls" drag>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
@@ -182,6 +184,26 @@
</span>
</template>
</el-dialog>
<!-- 导入操行考核弹窗 -->
<el-dialog title="导入操行考核数据" v-model="conductImportDialogVisible" :width="500" :close-on-click-modal="false" draggable>
<div style="margin-bottom: 15px">
<el-button icon="Download" type="success" @click="handleDownloadConductTemplate"> 下载模板 </el-button>
</div>
<el-upload :auto-upload="false" :on-change="handleConductFileChange" :limit="1" accept=".xlsx,.xls" drag>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">只能上传 xlsx/xls 文件请先下载导入模板</div>
</template>
</el-upload>
<template #footer>
<span class="dialog-footer">
<el-button @click="conductImportDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleConductImportSubmit" :disabled="!conductImportFile || conductImportLoading">确认导入</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
@@ -190,6 +212,7 @@ import { reactive, ref, onMounted, computed, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj, importExcel } from '/@/api/stuwork/stuconduct';
import { exportConductAssessmentTemplate, importConductAssessment, downloadBlobFile } from '/@/api/stuwork/file';
import { getDeptList } from '/@/api/basic/basicclass';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getClassListByRole } from '/@/api/basic/basicclass';
@@ -230,6 +253,9 @@ const typeList = ref<any[]>([]);
const importDialogVisible = ref(false);
const importFile = ref<File | null>(null);
const importLoading = ref(false);
const conductImportDialogVisible = ref(false);
const conductImportFile = ref<File | null>(null);
const conductImportLoading = ref(false);
// 表格列配置
const tableColumns = [
@@ -365,6 +391,49 @@ const handleImportSubmit = async () => {
}
};
// 下载操行考核导入模板
const handleDownloadConductTemplate = async () => {
try {
await downloadBlobFile(exportConductAssessmentTemplate(), `操行考核导入模板_${Date.now()}.xlsx`);
} catch (err: any) {
useMessage().error(err?.msg || '下载模板失败');
}
};
// 打开操行考核导入弹窗
const handleConductImport = () => {
conductImportDialogVisible.value = true;
conductImportFile.value = null;
};
// 操行考核文件变化
const handleConductFileChange = (file: any) => {
conductImportFile.value = file.raw;
};
// 提交操行考核导入
const handleConductImportSubmit = async () => {
if (!conductImportFile.value) {
useMessage().warning('请先选择要上传的文件');
return;
}
conductImportLoading.value = true;
try {
const formData = new FormData();
formData.append('file', conductImportFile.value);
await importConductAssessment(formData);
useMessage().success('导入成功');
conductImportDialogVisible.value = false;
conductImportFile.value = null;
getDataList();
} catch (err: any) {
useMessage().error(err.msg || '导入失败');
} finally {
conductImportLoading.value = false;
}
};
// 编辑
const handleEdit = (row: any) => {
formDialogRef.value?.openDialog('edit', row);

View File

@@ -5,18 +5,47 @@
<el-row v-show="showSearch">
<el-form :model="queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList">
<el-form-item label="学年" prop="schoolYear">
<el-select v-model="queryForm.schoolYear" placeholder="请选择学年" clearable filterable style="width: 200px">
<el-option v-for="item in schoolYearList" :key="item.year" :label="item.year" :value="item.year"> </el-option>
<el-select
v-model="queryForm.schoolYear"
placeholder="请选择学年"
clearable
filterable
style="width: 200px">
<el-option
v-for="item in schoolYearList"
:key="item.year"
:label="item.year"
:value="item.year">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="学期" prop="schoolTerm">
<el-select v-model="queryForm.schoolTerm" placeholder="请选择学期" clearable style="width: 200px">
<el-option v-for="item in schoolTermList" :key="item.value" :label="item.label" :value="item.value"> </el-option>
<el-select
v-model="queryForm.schoolTerm"
placeholder="请选择学期"
clearable
style="width: 200px">
<el-option
v-for="item in schoolTermList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="班级" prop="classCode">
<el-select v-model="queryForm.classCode" placeholder="请选择班级" clearable filterable style="width: 200px">
<el-option v-for="item in classList" :key="item.classCode" :label="item.classNo" :value="item.classCode"> </el-option>
<el-select
v-model="queryForm.classCode"
placeholder="请选择班级"
clearable
filterable
style="width: 200px">
<el-option
v-for="item in classList"
:key="item.classCode"
:label="item.classNo"
:value="item.classCode">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
@@ -74,7 +103,12 @@
</div>
<!-- 查看详情弹窗接口queryDataByStuNo 通过学年学号查看详情按当前学期筛选 -->
<el-dialog v-model="viewDialogVisible" title="学期操行考核详情" width="800px" destroy-on-close @close="viewDetailList = []">
<el-dialog
v-model="viewDialogVisible"
title="学期操行考核详情"
width="800px"
destroy-on-close
@close="viewDetailList = []">
<div v-if="viewRow" class="view-summary">
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="学号">{{ viewRow.stuNo }}</el-descriptions-item>
@@ -94,8 +128,7 @@
size="small"
max-height="400"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
:header-cell-style="tableStyle.headerCellStyle">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="schoolTerm" label="学期" width="80" align="center" show-overflow-tooltip />
<el-table-column prop="recordDate" label="考核日期" width="110" align="center" show-overflow-tooltip />
@@ -122,12 +155,12 @@
</template>
<script setup lang="ts" name="StuConductTerm">
import { reactive, ref, onMounted, computed } from 'vue';
import { getStuConductTerm, queryDataByStuNo, sendConductWarning } from '/@/api/stuwork/stuconduct';
import { getClassListByRole } from '/@/api/basic/basicclass';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getDicts } from '/@/api/admin/dict';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { reactive, ref, onMounted, computed } from 'vue'
import { getStuConductTerm, queryDataByStuNo, sendConductWarning } from "/@/api/stuwork/stuconduct";
import { getClassListByRole } from "/@/api/basic/basicclass";
import { queryAllSchoolYear } from "/@/api/basic/basicyear";
import { getDicts } from "/@/api/admin/dict";
import { useMessage, useMessageBox } from "/@/hooks/message";
// 表格样式 - 在组件内部定义,不从外部导入
const tableStyle = {
@@ -136,18 +169,18 @@ const tableStyle = {
};
// 定义变量内容
const searchFormRef = ref();
const showSearch = ref(true);
const loading = ref(false);
const warningLoading = ref(false);
const schoolYearList = ref<any[]>([]);
const schoolTermList = ref<any[]>([]);
const classList = ref<any[]>([]);
const studentList = ref<any[]>([]);
const viewDialogVisible = ref(false);
const viewLoading = ref(false);
const viewRow = ref<any>(null);
const viewDetailList = ref<any[]>([]);
const searchFormRef = ref()
const showSearch = ref(true)
const loading = ref(false)
const warningLoading = ref(false)
const schoolYearList = ref<any[]>([])
const schoolTermList = ref<any[]>([])
const classList = ref<any[]>([])
const studentList = ref<any[]>([])
const viewDialogVisible = ref(false)
const viewLoading = ref(false)
const viewRow = ref<any>(null)
const viewDetailList = ref<any[]>([])
// 查询表单
const queryForm = reactive({

View File

@@ -254,34 +254,20 @@
</template>
<script setup lang="ts" name="StuLeaveApply">
import { reactive, ref, onMounted, computed, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, exportData, cancelObj } from '/@/api/stuwork/stuleaveapply';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getDicts } from '/@/api/admin/dict';
import { getDeptListByLevelTwo } from '/@/api/basic/basicdept';
import { getClassListByRole } from '/@/api/basic/basicclass';
import { useMessage, useMessageBox } from '/@/hooks/message';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import FormDialog from './form.vue';
import {
List,
Calendar,
Clock,
OfficeBuilding,
Avatar,
Collection,
Document,
House,
Warning,
CircleCheck,
EditPen,
Setting,
Menu,
Search,
} from '@element-plus/icons-vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
import { reactive, ref, onMounted, computed, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, cancelObj } from "/@/api/stuwork/stuleaveapply";
import { makeExportStudentLeaveTask } from "/@/api/stuwork/file";
import { queryAllSchoolYear } from "/@/api/basic/basicyear";
import { getDicts } from "/@/api/admin/dict";
import { getDeptListByLevelTwo } from "/@/api/basic/basicdept";
import { getClassListByRole } from "/@/api/basic/basicclass";
import { useMessage, useMessageBox } from "/@/hooks/message";
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
import FormDialog from './form.vue'
import { List, Calendar, Clock, OfficeBuilding, Avatar, Collection, Document, House, Warning, CircleCheck, EditPen, Setting, Menu, Search } from '@element-plus/icons-vue'
import { useTableColumnControl } from '/@/hooks/tableColumn'
import { defineAsyncComponent } from 'vue';
const StatusTag = defineAsyncComponent(() => import('/@/components/StatusTag/index.vue'));
@@ -449,22 +435,12 @@ const handleCancel = async (row: any) => {
// 导出
const handleExport = async () => {
try {
const res = await exportData(searchForm);
// 处理返回的文件流
const blob = new Blob([res.data]);
const elink = document.createElement('a');
elink.download = '学生请假.xlsx';
elink.style.display = 'none';
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
useMessage().success('导出成功');
await makeExportStudentLeaveTask(searchForm)
useMessage().success('导出任务已创建,请在文件管理中下载')
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
useMessage().error(err.msg || '导出失败')
}
};
}
// 获取学年列表
const getSchoolYearList = async () => {

View File

@@ -191,33 +191,20 @@
</template>
<script setup lang="ts" name="StuPunlish">
import { reactive, ref, onMounted, computed, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj, exportData, revokePunishment, getDetail } from '/@/api/stuwork/stupunlish';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getDicts } from '/@/api/admin/dict';
import { getDeptListByLevelTwo } from '/@/api/basic/basicdept';
import { getClassListByRole } from '/@/api/basic/basicclass';
import { useMessage, useMessageBox } from '/@/hooks/message';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import FormDialog from './form.vue';
import {
List,
Calendar,
Clock,
OfficeBuilding,
Grid,
Avatar,
CreditCard,
Warning,
Document,
CircleCheck,
Setting,
Menu,
Search,
} from '@element-plus/icons-vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
import { reactive, ref, onMounted, computed, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, delObj, revokePunishment, getDetail } from "/@/api/stuwork/stupunlish";
import { makeExportStudentDisciplineTask } from "/@/api/stuwork/file";
import { queryAllSchoolYear } from "/@/api/basic/basicyear";
import { getDicts } from "/@/api/admin/dict";
import { getDeptListByLevelTwo } from "/@/api/basic/basicdept";
import { getClassListByRole } from "/@/api/basic/basicclass";
import { useMessage, useMessageBox } from "/@/hooks/message";
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
import FormDialog from './form.vue'
import { List, Calendar, Clock, OfficeBuilding, Grid, Avatar, CreditCard, Warning, Document, CircleCheck, Setting, Menu, Search } from '@element-plus/icons-vue'
import { useTableColumnControl } from '/@/hooks/tableColumn'
import { defineAsyncComponent } from 'vue';
const StatusTag = defineAsyncComponent(() => import('/@/components/StatusTag/index.vue'));
@@ -414,30 +401,20 @@ const handleCancel = async (row: any) => {
// 导出
const handleExport = async () => {
try {
const params: any = { ...searchForm };
const params: any = { ...searchForm }
// 处理处分月份参数 API
if (params.punlishMonth) {
params.punlishMonth = [params.punlishMonth];
params.punlishMonth = [params.punlishMonth]
} else {
delete params.punlishMonth;
delete params.punlishMonth
}
delete params.punlishMonthArray;
const res = await exportData(params);
// 下载文件
const blob = new Blob([res.data]);
const elink = document.createElement('a');
elink.download = '学生处分.xlsx';
elink.style.display = 'none';
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
useMessage().success('导出成功');
delete params.punlishMonthArray
await makeExportStudentDisciplineTask(params)
useMessage().success('导出任务已创建,请在文件管理中下载')
} catch (err: any) {
useMessage().error(err.msg || '导出失败');
useMessage().error(err.msg || '导出失败')
}
};
}
// 获取学年列表
const getSchoolYearList = async () => {

View File

@@ -257,7 +257,8 @@
import { reactive, ref, onMounted, computed, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, delObj, exportData, cancelObj } from "/@/api/stuwork/stuturnover";
import { fetchList, delObj, cancelObj } from "/@/api/stuwork/stuturnover";
import { makeExportStudentChangeTask } from "/@/api/stuwork/file";
import { queryAllSchoolYear } from "/@/api/basic/basicyear";
import { getDicts } from "/@/api/admin/dict";
import { getDeptListByLevelTwo } from "/@/api/basic/basicdept";
@@ -438,18 +439,8 @@ const handleDelete = async (row: any) => {
// 导出
const handleExport = async () => {
try {
const res = await exportData(searchForm)
// 处理返回的文件流
const blob = new Blob([res.data])
const elink = document.createElement('a')
elink.download = '学籍异动.xlsx'
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href)
document.body.removeChild(elink)
useMessage().success('导出成功')
await makeExportStudentChangeTask(searchForm)
useMessage().success('导出任务已创建,请在文件管理中下载')
} catch (err: any) {
useMessage().error(err.msg || '导出失败')
}

View File

@@ -272,6 +272,7 @@ import { reactive, ref, onMounted, computed, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, delObjs, initWaterOrder } from "/@/api/stuwork/waterdetail";
import { makeExportDormWaterElectricityTask } from "/@/api/stuwork/file";
import { getBuildingList } from "/@/api/stuwork/dormbuilding";
import { useMessage, useMessageBox } from "/@/hooks/message";
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
@@ -410,9 +411,13 @@ const handleDelete = async (row: any) => {
}
// 导出
const handleExport = () => {
// TODO: 实现导出
useMessage().warning('功能开发中')
const handleExport = async () => {
try {
await makeExportDormWaterElectricityTask(searchForm)
useMessage().success('导出任务已创建,请在文件管理中下载')
} catch (err: any) {
useMessage().error(err.msg || '导出失败')
}
}
// 统计分析