This commit is contained in:
zhouwentao 2025-02-18 16:30:52 +08:00
parent c1ae3394f9
commit e04fe73c2c
47 changed files with 5969 additions and 709 deletions

2
.gitignore vendored
View File

@ -24,7 +24,7 @@ pnpm-debug.log*
.idea .idea
.svn .svn
# .vscode # .vscode
*.suo *.suo·
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln

View File

@ -129,10 +129,15 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
} }
// 显示详细信息 // 显示详细信息
console.log('qqq');
if (column.params?.showDetails) { if (column.params?.showDetails) {
refs.detailsModalRef.value?.open(event); refs.detailsModalRef.value?.open(event);
} else if (refs.subPopoverRef.value) { } else if (refs.subPopoverRef.value) {
refs.subPopoverRef.value.toggle(event); if (column.params?.showSub !== false) {
refs.subPopoverRef.value.toggle(event);
}
// if (column.params?.showSub !== undefined) {
// }
} else if (props.clickSelectRow) { } else if (props.clickSelectRow) {
let className = $event.target.className || ''; let className = $event.target.className || '';
className = isString(className) ? className : className.toString(); className = isString(className) ? className : className.toString();

View File

@ -3,6 +3,7 @@ import { defHttp } from '/@/utils/http/axios';
enum Api { enum Api {
loginfo = '/sys/loginfo', loginfo = '/sys/loginfo',
visitInfo = '/sys/visitInfo', visitInfo = '/sys/visitInfo',
logStatistics = '/sys/logStatistics',
} }
/** /**
* *
@ -14,3 +15,5 @@ export const getLoginfo = (params) => defHttp.get({ url: Api.loginfo, params },
* @param params * @param params
*/ */
export const getVisitInfo = (params) => defHttp.get({ url: Api.visitInfo, params }, { isTransformResponse: false }); export const getVisitInfo = (params) => defHttp.get({ url: Api.visitInfo, params }, { isTransformResponse: false });
export const getLogStatistics = (params) => defHttp.post({ url: Api.logStatistics, params }, { isTransformResponse: false });

View File

@ -4,26 +4,31 @@
<a-tabs default-active-key="1" size="large" :tab-bar-style="{ marginBottom: '24px', paddingLeft: '16px' }"> <a-tabs default-active-key="1" size="large" :tab-bar-style="{ marginBottom: '24px', paddingLeft: '16px' }">
<template #rightExtra> <template #rightExtra>
<div class="extra-wrapper"> <div class="extra-wrapper">
<div class="extra-item"> <div class="extra-item" style="position: relative">
<a>今日</a> <!-- <div>-->
<a>本周</a> <!-- <a-radio-group v-model:value="value1" button-style="solid" @change="value1Change">-->
<a>本月</a> <!-- <a-radio-button value="today">本日</a-radio-button>-->
<a>本年</a> <!-- <a-radio-button value="days">按天</a-radio-button>-->
<!-- <a-radio-button value="month">按月</a-radio-button>-->
<!-- <a-radio-button value="year">按年</a-radio-button>-->
<!-- </a-radio-group>-->
<!-- </div>-->
</div> </div>
<a-range-picker :style="{ width: '256px' }" /> <!-- <a-range-picker @change="rangePickerChange" v-if="value1 == 'month'" v-model:value="rangePickerData" picker="month" :style="{ width: '256px' }" />-->
<a-range-picker v-if="value1 == 'days'" @change="rangePickerChange" v-model:value="rangePickerData" :style="{ width: '256px' }" />
</div> </div>
</template> </template>
<a-tab-pane loading="true" tab="销售额" key="1"> <a-tab-pane loading="true" tab="销售额" key="1">
<a-row> <a-row>
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24"> <a-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
<Bar :chartData="barData" :option="{ title: { text: '销售额排行', textStyle: { fontWeight: 'lighter' } } }" height="40vh" /> <Bar :chartData="barData" :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }" height="40vh" />
</a-col>
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
<RankList title="门店销售排行榜" :list="rankList" />
</a-col> </a-col>
<!-- <a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">-->
<!-- <RankList title="门店销售排行榜" :list="rankList" />-->
<!-- </a-col>-->
</a-row> </a-row>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="销售趋势" key="2"> <!-- <a-tab-pane tab="销售趋势" key="2">
<a-row> <a-row>
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24"> <a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
<Bar :chartData="barData.reverse()" :option="{ title: { text: '销售额排行', textStyle: { fontWeight: 'lighter' } } }" height="40vh" /> <Bar :chartData="barData.reverse()" :option="{ title: { text: '销售额排行', textStyle: { fontWeight: 'lighter' } } }" height="40vh" />
@ -32,16 +37,20 @@
<RankList title="门店销售排行榜" :list="rankList" /> <RankList title="门店销售排行榜" :list="rankList" />
</a-col> </a-col>
</a-row> </a-row>
</a-tab-pane> </a-tab-pane>-->
</a-tabs> </a-tabs>
</div> </div>
</a-card> </a-card>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import type { Dayjs } from 'dayjs';
import { getLogStatistics } from '../api';
import Bar from '/@/components/chart/Bar.vue'; import Bar from '/@/components/chart/Bar.vue';
import RankList from '/@/components/chart/RankList.vue'; type RangeValue = [Dayjs, Dayjs];
const dateFormat = 'YYYY/MM/DD';
const value1 = ref<string>('days');
const rangePickerData = ref<RangeValue>();
defineProps({ defineProps({
loading: { loading: {
type: Boolean, type: Boolean,
@ -62,6 +71,31 @@
value: Math.floor(Math.random() * 1000) + 200, value: Math.floor(Math.random() * 1000) + 200,
}); });
} }
function value1Change(){
console.log(rangePickerData);
}
function rangePickerChange(data){
console.log(data);
console.log(data[0].format(dateFormat));
data[1].format(dateFormat);
console.log(data[0]);
}
function fff() {
const params = {
type:'day',
dayStart:'2024-08-29',
dayEnd:'2024-08-29',
};
getLogStatistics(params).then((res) => {
if (res.success) {
console.log(res);
}
});
}
fff();
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="p-4"> <div class="p-4">
<ChartGroupCard class="enter-y" :loading="loading" type="chart" /> <!-- <ChartGroupCard class="enter-y" :loading="loading" type="chart" />-->
<SaleTabCard class="!my-4 enter-y" :loading="loading" /> <SaleTabCard class="!my-4 enter-y" :loading="loading" />
<a-row> <a-row>
<a-col :span="24"> <a-col :span="24">
@ -21,6 +21,12 @@
</a-col> </a-col>
</a-row> </a-row>
</div> </div>
<!-- <div style="position: absolute;z-index: 100;left: 200px;top: 50px">-->
<!-- <a-button @click="openNotification('bottomRight')">-->
<!-- <template #icon><radius-bottomright-outlined /></template>-->
<!-- 属性介绍-->
<!-- </a-button>-->
<!-- </div>-->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
@ -29,6 +35,23 @@
import LineMulti from '/@/components/chart/LineMulti.vue'; import LineMulti from '/@/components/chart/LineMulti.vue';
import HeadInfo from '/@/components/chart/HeadInfo.vue'; import HeadInfo from '/@/components/chart/HeadInfo.vue';
import { getLoginfo, getVisitInfo } from '../api.ts'; import { getLoginfo, getVisitInfo } from '../api.ts';
import { notification } from 'ant-design-vue';
import type { NotificationPlacement } from 'ant-design-vue';
const openNotification = (placement: NotificationPlacement) => {
notification.open({
message: `访问量统计说明`,
description:
'今日IP当日的访问中存在的IP数量.' +
'\n\n今日访问数量当天0点到当天23点59分范围内访问系统的次数,部分请求不计入次数(如反复查询学校、志愿模拟数据等多次请求事件仅会统计一次).' +
'\n\n总访问量全部的访问量从系统启动到当前时间内接收到的请求数量' +
'\n\n详细日志可以查看日志管理模块预览',
placement,
style: {
//width: '600px',
whiteSpace: 'pre-wrap',
},
});
};
const loading = ref(true); const loading = ref(true);
@ -53,13 +76,14 @@
lineMultiData.value = []; lineMultiData.value = [];
res.result.forEach((item) => { res.result.forEach((item) => {
lineMultiData.value.push({ name: item.type, type: 'ip', value: item.ip }); lineMultiData.value.push({ name: item.type, type: 'ip', value: item.ip });
lineMultiData.value.push({ name: item.type, type: 'visit', value: item.visit }); lineMultiData.value.push({ name: item.type, type: '总次数', value: item.visit });
}); });
} }
}); });
} }
initLogInfo(); initLogInfo();
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -3,13 +3,13 @@
<div class=""> <div class="">
艺体志愿宝 艺体志愿宝
</div> </div>
<!-- <GrowCard :loading="loading" class="enter-y" /> <GrowCard :loading="loading" class="enter-y" />
<SiteAnalysis class="!my-4 enter-y" :loading="loading" /> <SiteAnalysis class="!my-4 enter-y" :loading="loading" />
<div class="md:flex enter-y"> <div class="md:flex enter-y">
<VisitRadar class="md:w-1/3 w-full" :loading="loading" /> <VisitRadar class="md:w-1/3 w-full" :loading="loading" />
<VisitSource class="md:w-1/3 !md:mx-4 !md:my-0 !my-4 w-full" :loading="loading" /> <VisitSource class="md:w-1/3 !md:mx-4 !md:my-0 !my-4 w-full" :loading="loading" />
<SalesProductPie class="md:w-1/3 w-full" :loading="loading" /> <SalesProductPie class="md:w-1/3 w-full" :loading="loading" />
</div>--> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -3,15 +3,15 @@
<IndexChart v-if="indexStyle === 1"></IndexChart> <IndexChart v-if="indexStyle === 1"></IndexChart>
<IndexBdc v-if="indexStyle == 2"></IndexBdc> <IndexBdc v-if="indexStyle == 2"></IndexBdc>
<IndexTask v-if="indexStyle == 3"></IndexTask> <IndexTask v-if="indexStyle == 3"></IndexTask>
<!-- <div style="width: 100%; text-align: right; margin-top: 20px"> <!-- <div style="width: 100%; text-align: right; margin-top: 20px">-->
请选择首页样式 <!-- 请选择首页样式-->
<a-radio-group v-model:value="indexStyle"> <!-- <a-radio-group v-model:value="indexStyle">-->
<a-radio :value="0">默认</a-radio> <!-- <a-radio :value="0">默认</a-radio>-->
<a-radio :value="1">销量统计</a-radio> <!-- <a-radio :value="1">销量统计</a-radio>-->
<a-radio :value="2">业务统计</a-radio> <!-- <a-radio :value="2">业务统计</a-radio>-->
<a-radio :value="3">我的任务</a-radio> <!-- <a-radio :value="3">我的任务</a-radio>-->
</a-radio-group> <!-- </a-radio-group>-->
</div>--> <!-- </div>-->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
@ -20,5 +20,5 @@
import IndexBdc from './homePage/IndexBdc.vue'; import IndexBdc from './homePage/IndexBdc.vue';
import IndexTask from './homePage/IndexTask.vue'; import IndexTask from './homePage/IndexTask.vue';
const indexStyle = ref(0); const indexStyle = ref(1);
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-if="visible" ref="aideWrapRef" class="aide-wrap" @click="handleGo"> <div v-show="false" ref="aideWrapRef" class="aide-wrap" @click="handleGo">
<div class="icon"> <div class="icon">
<svg t="1706259688149" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2056" width="17" height="17"> <svg t="1706259688149" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2056" width="17" height="17">
<path <path

View File

@ -7,7 +7,8 @@
</a-tabs> </a-tabs>
</template> </template>
<template #expandedRowRender="{ record }"> <template #expandedRowRender="{ record }">
<div v-if="searchInfo.logType == 2"> <div v-if="searchInfo.logType">
<!--searchInfo.logType == 2-->
<div style="margin-bottom: 5px"> <div style="margin-bottom: 5px">
<a-badge status="success" style="vertical-align: middle" /> <a-badge status="success" style="vertical-align: middle" />
<span style="vertical-align: middle">请求方法:{{ record.method }}</span></div <span style="vertical-align: middle">请求方法:{{ record.method }}</span></div

View File

@ -0,0 +1,42 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="修改密码" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" name="PassWordModal" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formPasswordSchema } from './user.data';
import { changePassword } from './user.api';
// Emits
const emit = defineEmits(['success', 'register']);
//
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: formPasswordSchema,
showActionButtonGroup: false,
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false });
//
await setFieldsValue({ ...data });
});
//
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//
await changePassword(values);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,45 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="用户代理" @ok="handleSubmit" destroyOnClose>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formAgentSchema } from './user.data';
import { getUserAgent, saveOrUpdateAgent } from './user.api';
// Emits
const emit = defineEmits(['success', 'register']);
//
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: formAgentSchema,
showActionButtonGroup: false,
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false });
//
const res = await getUserAgent({ userName: data.userName });
data = res.result ? res.result : data;
//
await setFieldsValue({ ...data });
});
//
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//
await saveOrUpdateAgent(values);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,160 @@
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
:title="getTitle"
:width="adaptiveWidth"
@ok="handleSubmit"
:showFooter="showFooter"
destroyOnClose
>
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { defineComponent, ref, computed, unref, useAttrs } from 'vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from './user.data';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { saveOrUpdateUser, getUserRoles, getUserDepartList, getAllRolesListNoByTenant, getAllRolesList } from './user.api';
import { useDrawerAdaptiveWidth } from '/@/hooks/jeecg/useAdaptiveWidth';
import { getTenantId } from "/@/utils/auth";
// Emits
const emit = defineEmits(['success', 'register']);
const attrs = useAttrs();
const isUpdate = ref(true);
const rowId = ref('');
const departOptions = ref([]);
//
const [registerForm, { setProps, resetFields, setFieldsValue, validate, updateSchema }] = useForm({
labelWidth: 90,
schemas: formSchema,
showActionButtonGroup: false,
});
// TODO [VUEN-527] https://www.teambition.com/task/6239beb894b358003fe93626
const showFooter = ref(true);
//
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
await resetFields();
showFooter.value = data?.showFooter ?? true;
setDrawerProps({ confirmLoading: false, showFooter: showFooter.value });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
rowId.value = data.record.id;
//
if (data.record.relTenantIds && !Array.isArray(data.record.relTenantIds)) {
data.record.relTenantIds = data.record.relTenantIds.split(',');
} else {
//issues/I56C5I
//data.record.relTenantIds = [];
}
////try catch
try {
const userRoles = await getUserRoles({ userid: data.record.id });
if (userRoles && userRoles.length > 0) {
data.record.selectedroles = userRoles;
}
} catch (error) {}
///
const userDepart = await getUserDepartList({ userId: data.record.id });
if (userDepart && userDepart.length > 0) {
data.record.selecteddeparts = userDepart;
let selectDepartKeys = Array.from(userDepart, ({ key }) => key);
data.record.selecteddeparts = selectDepartKeys.join(',');
departOptions.value = userDepart.map((item) => {
return { label: item.title, value: item.key };
});
}
///
data.record.departIds && !Array.isArray(data.record.departIds) && (data.record.departIds = data.record.departIds.split(','));
//update-begin---author:zyf Date:20211210 for------------
//update-begin---author:liusq Date:20231008 for[issues/772]------------
data.record.departIds = (!data.record.departIds || data.record.departIds == '') ? [] : data.record.departIds;
//update-end-----author:liusq Date:20231008 for[issues/772]------------
//update-begin---author:zyf Date:20211210 for------------
}
//()
data.selectedroles && (await setFieldsValue({ selectedroles: data.selectedroles }));
////
updateSchema([
{
field: 'password',
// QQYUN-8324
ifShow: !unref(isUpdate),
},
{
field: 'confirmPassword',
ifShow: !unref(isUpdate),
},
{
field: 'selectedroles',
show: !data.isRole,
},
{
field: 'departIds',
componentProps: { options: departOptions },
},
{
field: 'selecteddeparts',
show: !data?.departDisabled ?? false,
},
{
field: 'selectedroles',
show: !data?.departDisabled ?? false,
//update-begin---author:wangshuai ---date:20230424 forissues/4844------------
//
componentProps:{
api: data.tenantSaas?getAllRolesList:getAllRolesListNoByTenant
}
//update-end---author:wangshuai ---date:20230424 forissues/4844------------
},
//update-begin---author:wangshuai ---date:20230522 forissues/4935------------
{
field: 'relTenantIds',
componentProps:{
disabled: !!data.tenantSaas,
},
},
//update-end---author:wangshuai ---date:20230522 forissues/4935------------
]);
//update-begin---author:wangshuai ---date:20230522 forissues/4935------------
if(!unref(isUpdate) && data.tenantSaas){
await setFieldsValue({ relTenantIds: getTenantId().toString() })
}
//update-end---author:wangshuai ---date:20230522 forissues/4935------------
//
if (typeof data.record === 'object') {
setFieldsValue({
...data.record,
});
}
//
//update-begin-author:taoyan date:2022-5-24 for: VUEN-1117issue0523
setProps({ disabled: !showFooter.value });
//update-end-author:taoyan date:2022-5-24 for: VUEN-1117issue0523
});
//
const getTitle = computed(() => (!unref(isUpdate) ? '新增用户' : '编辑用户'));
const { adaptiveWidth } = useDrawerAdaptiveWidth();
//
async function handleSubmit() {
try {
let values = await validate();
setDrawerProps({ confirmLoading: true });
values.userIdentity === 1 && (values.departIds = '');
let isUpdateVal = unref(isUpdate);
//
await saveOrUpdateUser(values, isUpdateVal);
//
closeDrawer();
//
emit('success',{isUpdateVal ,values});
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,81 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="离职交接" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup name="user-quit-agent-modal">
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formQuitAgentSchema } from './user.data';
import { getUserAgent, userQuitAgent } from './user.api';
import dayjs from 'dayjs';
// Emits
const emit = defineEmits(['success', 'register']);
//
const [registerForm, { resetFields, setFieldsValue, validate, clearValidate, updateSchema }] = useForm({
schemas: formQuitAgentSchema,
showActionButtonGroup: false,
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: true });
let userId = data.userId;
//
const res = await getUserAgent({ userName: data.userName });
data = res.result ? res.result : data;
let date = new Date();
if (!data.startTime) {
data.startTime = dayjs(date).format('YYYY-MM-DD HH:mm:ss');
}
if (!data.endTime) {
data.endTime = getYear(date);
}
//update-begin---author:wangshuai ---date:20230703 forQQYUN-56855------------
await updateSchema(
[{
field:'agentUserName',
componentProps:{
excludeUserIdList:[userId]
}
}]
)
//update-end---author:wangshuai ---date:20230703 forQQYUN-56855------------
//
await setFieldsValue({ ...data });
setModalProps({ confirmLoading: false });
});
//
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//
await userQuitAgent(values);
//
closeModal();
//
emit('success',values.userName);
} finally {
setModalProps({ confirmLoading: false });
}
}
/**
* 获取后30年
*/
function getYear(date) {
//update-begin---author:wangshuai ---date:20221207 for[QQYUN-3285] ------------
//
let y = date.getFullYear() + 30;
let m = dayjs(date).format('MM');
let d = dayjs(date).format('DD');
let hour = dayjs(date).format('HH:mm:ss');
console.log('年月日', y + '-' + m + '-' + d);
return dayjs(y + '-' + m + '-' + d + ' ' + hour).format('YYYY-MM-DD HH:mm:ss');
//update-end---author:wangshuai ---date:20221207 for[QQYUN-3285] --------------
}
</script>

View File

@ -0,0 +1,110 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="离职人员信息" :showOkBtn="false" width="1000px" destroyOnClose>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleRevert">
<Icon icon="ant-design:redo-outlined"></Icon>
批量取消
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="ant-design:down-outlined"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts" setup name="user-quit-modal">
import { ref, toRaw, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { recycleColumns } from './user.data';
import { getQuitList, putCancelQuit, deleteRecycleBin } from './user.api';
import { useMessage } from '/@/hooks/web/useMessage';
import { useListPage } from '/@/hooks/system/useListPage';
import { Modal } from 'ant-design-vue';
import { defHttp } from '/@/utils/http/axios';
const { createConfirm } = useMessage();
// Emits
const emit = defineEmits(['success', 'register']);
const checkedKeys = ref<Array<string | number>>([]);
const [registerModal] = useModalInner(() => {
checkedKeys.value = [];
});
//table
const { prefixCls, tableContext } = useListPage({
tableProps: {
api: getQuitList,
columns: recycleColumns,
rowKey: 'id',
canResize: false,
useSearchForm: false,
actionColumn: {
width: 120,
},
},
});
//table
const [registerTable, { reload }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
/**
* 取消离职事件
* @param record
*/
async function handleCancelQuit(record) {
await putCancelQuit({ userIds: record.id, usernames: record.username }, reload);
emit('success');
}
/**
* 批量取消离职事件
*/
function batchHandleRevert() {
Modal.confirm({
title: '取消离职',
content: '取消离职交接人也会清空',
okText: '确认',
cancelText: '取消',
onOk: () => {
let rowValue = selectedRows.value;
let rowData: any = [];
for (const value of rowValue) {
rowData.push(value.username);
}
handleCancelQuit({ id: toRaw(unref(selectedRowKeys)).join(','), username: rowData.join(',') });
},
});
}
//
function getTableAction(record) {
return [
{
label: '取消离职',
icon: 'ant-design:redo-outlined',
popConfirm: {
title: '是否取消离职,取消离职交接人也会清空',
confirm: handleCancelQuit.bind(null, record),
},
},
];
}
</script>
<style scoped lang="less">
:deep(.ant-popover-inner-content){
width: 185px !important;
}
</style>

View File

@ -0,0 +1,138 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="用户回收站" :showOkBtn="false" width="1000px" destroyOnClose>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-dropdown v-if="checkedKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
批量删除
</a-menu-item>
<a-menu-item key="1" @click="batchHandleRevert">
<Icon icon="ant-design:redo-outlined"></Icon>
批量还原
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="ant-design:down-outlined"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction :actions="getTableAction(record)" />
</template>
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, toRaw, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { recycleColumns } from './user.data';
import { getRecycleBinList, putRecycleBin, deleteRecycleBin } from './user.api';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
// Emits
const emit = defineEmits(['success', 'register']);
const checkedKeys = ref<Array<string | number>>([]);
const [registerModal] = useModalInner(() => {
checkedKeys.value = [];
});
//table
const [registerTable, { reload }] = useTable({
api: getRecycleBinList,
columns: recycleColumns,
rowKey: 'id',
striped: true,
useSearchForm: false,
showTableSetting: false,
clickToRowSelect: false,
bordered: true,
showIndexColumn: false,
pagination: true,
tableSetting: { fullScreen: true },
canResize: false,
actionColumn: {
width: 150,
title: '操作',
dataIndex: 'action',
// slots: { customRender: 'action' },
fixed: undefined,
},
});
/**
* 选择列配置
*/
const rowSelection = {
type: 'checkbox',
columnWidth: 50,
selectedRowKeys: checkedKeys,
onChange: onSelectChange,
};
/**
* 选择事件
*/
function onSelectChange(selectedRowKeys: (string | number)[]) {
checkedKeys.value = selectedRowKeys;
}
/**
* 还原事件
*/
async function handleRevert(record) {
await putRecycleBin({ userIds: record.id }, reload);
emit('success');
}
/**
* 批量还原事件
*/
function batchHandleRevert() {
handleRevert({ id: toRaw(unref(checkedKeys)).join(',') });
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteRecycleBin({ userIds: record.id }, reload);
}
/**
* 批量删除事件
*/
function batchHandleDelete() {
createConfirm({
iconType: 'warning',
title: '删除',
content: '确定要永久删除吗?删除后将不可恢复!',
onOk: () => handleDelete({ id: toRaw(unref(checkedKeys)).join(',') }),
onCancel() {},
});
}
//
function getTableAction(record) {
return [
{
label: '取回',
icon: 'ant-design:redo-outlined',
popConfirm: {
title: '是否确认还原',
confirm: handleRevert.bind(null, record),
},
},
{
label: '彻底删除',
icon: 'ant-design:scissor-outlined',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
];
}
</script>

View File

@ -0,0 +1,355 @@
<template>
<a-card title="" :bordered="false">
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam"
:label-col="labelCol" :wrapper-col="wrapperCol">
<a-row>
<a-col :span="4">
<a-form-item label="手机号">
<a-input v-model:value="queryParam.phone" placeholder="请输入手机号" allowClear/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="exportXls" style="margin: 8px">导出</a-button>-->
<!-- <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls" style="margin-left: 8px">导入</j-upload-button>-->
</a-col>
</a-row>
</a-form>
<JVxeTable
toolbar
:toolbarConfig="toolbarConfig"
rowNumber
rowSelection
keepSource
asyncRemove
:height="500"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:pagination="pagination"
@save="handleTableSave"
@removed="handleTableRemove"
@edit-closed="handleEditClosed"
@pageChange="handlePageChange"
@valueChange="handleValueChange"
@selectRowChange="handleSelectRowChange"
/>
</a-card>
</template>
<script lang="ts" setup>
//
import {reactive, ref} from 'vue';
import { message } from 'ant-design-vue';
import {defHttp} from '/@/utils/http/axios';
import {JVxeColumn, JVxeTypes} from '/@/components/jeecg/JVxeTable/types';
import {useMessage} from '/@/hooks/web/useMessage';
import {useListPage} from "@/hooks/system/useListPage";
import {getExportUrl, getImportUrl, list} from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api";
import {XLSX_FILE_SUFFIX, XLSX_MIME_TYPE} from "@/hooks/system/useMethods";
import { render } from "@/utils/common/renderUtils";
const { createMessage, createConfirm, createSuccessModal, createInfoModal, createErrorModal, createWarningModal, notification } = useMessage();
const labelCol = reactive({
xs: {span: 24},
sm: {span: 7},
});
const wrapperCol = reactive({
xs: {span: 24},
sm: {span: 16},
});
//
const toolbarConfig = reactive({
// add remove clearSelection
// btn: ['add', 'save', 'remove', 'clearSelection'],
btn: [],
});
//
const loading = ref(false);
//
const queryParam = reactive({
phone: '',
})
//
const pagination = reactive({
//
current: 1,
//
pageSize: 10,
//
pageSizeOptions: ['10', '20', '30', '100', '200'],
// 0
total: 0,
});
//
const selectedRows = ref<Recordable[]>([]);
//
const dataSource = ref<Recordable[]>([]);
//
const columns = ref<JVxeColumn[]>([
/*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/
{
title: '用户账号',
key: 'username',
type: JVxeTypes.input,
},
{
title: '用户姓名',
key: 'realname',
type: JVxeTypes.input,
},
{
title: '性别',
key: 'sex',
},
{
title: '手机号',
key: 'phone',
type: JVxeTypes.input,
},
{
title: '显示历年线差',
key: 'showLinediff',
type: JVxeTypes.checkbox,
width: 100,
customValue: ['1', '0'], // true ,false
},
{
title: '状态',
key: 'status_dictText',
width: 150,
},
]);
const [messageApi, contextHolder] = message.useMessage();
const { prefixCls,tableContext,onImportXls } = useListPage({
tableProps:{
title: '历年录取数据表',
canResize:false,
},
importConfig:{
url: getImportUrl,
success: handleSuccess
}
})
// url
enum Api {
getData = '/sys/user/list',
//
saveRow = '/sys/user/edit',
//
saveAll = '/yx/yxHistoryMajorEnroll/saveBatch',
deleteBatch = '/yx/yxHistoryMajorEnroll/deleteBatch',
importExcel = '/yx/yxHistoryMajorEnroll/importExcel',
exportXls = '/yx/yxHistoryMajorEnroll/exportXlsBySchoolMajor',
renewControlLine = '/yx/yxHistoryMajorEnroll/renewControlLine'
}
loadData();
async function searchQuery() {
pagination.current = 1
loadData()
}
async function searchReset() {
pagination.current = 1
queryParam.phone = ''
loadData()
}
//
async function loadData() {
loading.value = true;
//
await defHttp
.get({
//
url: Api.getData,
//
params: {
phone: queryParam.phone ? '*' + queryParam.phone + '*' : '',
pageNo: pagination.current,
pageSize: pagination.pageSize,
},
})
.then((result) => {
// total
pagination.total = result.total;
// dataSource
dataSource.value = result.records;
//
selectedRows.value = [];
})
.finally(() => {
// loading
loading.value = false;
});
}
//
function handleTableSave({$table, target}) {
//
$table.validate().then((errMap) => {
//
if (!errMap) {
//
let tableData = target.getTableData();
console.log('当前保存的数据是:', tableData);
//
let newData = target.getNewData();
console.log('-- 新增的数据:', newData);
//
let deleteData = target.getDeleteData();
console.log('-- 删除的数据:', deleteData);
//
loading.value = true;
defHttp
.post({
url: Api.saveAll,
params: tableData,
})
.then(() => {
createMessage.success(`保存成功!`);
})
.finally(() => {
loading.value = false;
});
}
});
}
//
function handleTableRemove(event) {
// event.deleteRows
console.log('待删除的数据: ', event.deleteRows);
// IDID
let deleteIds = event.deleteRows.map((row) => row.id);
console.log('待删除的数据ids: ', deleteIds);
//
loading.value = true;
window.setTimeout(() => {
defHttp
.delete({
url: Api.deleteBatch, data: {ids: deleteIds.join(',')}
}, {joinParamsToUrl: true})
.then((res) => {
createMessage.success('删除成功');
//// confirmRemove()
event.confirmRemove();
})
.finally(() => {
loading.value = false;
});
}, 1000);
}
function handleValueChange(event) {
console.log('handleValueChange.event: ', event);
let {$table, row, column} = event;
let field = column.property;
console.log(row)
handleEditClosed(event)
}
//
function handleEditClosed(event) {
let {$table, row, column} = event;
let field = column.property;
//
if ($table.isUpdateByRow(row, field)) {
//
$table.validate(row).then((errMap) => {
//
if (!errMap) {
//
let hideLoading = createMessage.loading(`正在保存"${column.title}"`, 0);
console.log('即时保存数据:', row);
defHttp
.put({
url: Api.saveRow,
params: row,
})
.then((res) => {
createMessage.success(`"${column.title}"保存成功!`);
//
$table.reloadRow(row, null, field);
})
.finally(() => {
hideLoading();
});
}
});
}
}
//
function handlePageChange(event) {
//
pagination.current = event.current;
pagination.pageSize = event.pageSize;
//
loadData();
}
/**
* 成功回调
*/
function handleSuccess() {
loadData();
}
//
function handleSelectRowChange(event) {
selectedRows.value = event.selectedRows;
}
/**
* 导出xls
* @param name
* @param url
*/
async function exportXls(isXlsx = false) {
let name = ''
let selections = ''
if (selectedRows.value) {
selectedRows.value.forEach(i=>{
selections+=i.id+","
})
console.log(selectedRows.value)
}
const data = await defHttp.get({ url: Api.exportXls, params: {selections:selections}, responseType: 'blob', timeout: 60000 }, { isTransformResponse: false });
if (!data) {
createMessage.warning('文件下载失败');
return;
}
if (!name || typeof name != 'string') {
name = '导出文件';
}
let blobOptions = { type: 'application/vnd.ms-excel' };
let fileSuffix = '.xls';
if (isXlsx === true) {
blobOptions['type'] = XLSX_MIME_TYPE;
fileSuffix = XLSX_FILE_SUFFIX;
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data], blobOptions), name + fileSuffix);
} else {
let url = window.URL.createObjectURL(new Blob([data], blobOptions));
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', name + fileSuffix);
document.body.appendChild(link);
link.click();
document.body.removeChild(link); //
window.URL.revokeObjectURL(url); //blob
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,242 @@
import { defHttp } from '/@/utils/http/axios';
import { Modal } from 'ant-design-vue';
enum Api {
listNoCareTenant = '/sys/user/listAll',
list = '/sys/user/list',
save = '/sys/user/add',
edit = '/sys/user/edit',
agentSave = '/sys/sysUserAgent/add',
agentEdit = '/sys/sysUserAgent/edit',
getUserRole = '/sys/user/queryUserRole',
duplicateCheck = '/sys/duplicate/check',
deleteUser = '/sys/user/delete',
deleteBatch = '/sys/user/deleteBatch',
importExcel = '/sys/user/importExcel',
exportXls = '/sys/user/exportXls',
recycleBinList = '/sys/user/recycleBin',
putRecycleBin = '/sys/user/putRecycleBin',
deleteRecycleBin = '/sys/user/deleteRecycleBin',
allRolesList = '/sys/role/queryall',
allRolesListNoByTenant = '/sys/role/queryallNoByTenant',
allTenantList = '/sys/tenant/queryList',
allPostList = '/sys/position/list',
userDepartList = '/sys/user/userDepartList',
changePassword = '/sys/user/changePassword',
frozenBatch = '/sys/user/frozenBatch',
getUserAgent = '/sys/sysUserAgent/queryByUserName',
userQuitAgent = '/sys/user/userQuitAgent',
getQuitList = '/sys/user/getQuitList',
putCancelQuit = '/sys/user/putCancelQuit',
updateUserTenantStatus='/sys/tenant/updateUserTenantStatus',
getUserTenantPageList='/sys/tenant/getUserTenantPageList',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
* ()
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* ()
* @param params
*/
export const listNoCareTenant = (params) => defHttp.get({ url: Api.listNoCareTenant, params });
/**
*
* @param params
*/
export const getUserRoles = (params) => defHttp.get({ url: Api.getUserRole, params }, { errorMessageMode: 'none' });
/**
*
*/
export const deleteUser = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteUser, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const batchDeleteUser = (params, handleSuccess) => {
Modal.confirm({
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
*
* @param params
*/
export const saveOrUpdateUser = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
/**
*
* @param params
*/
export const duplicateCheck = (params) => defHttp.get({ url: Api.duplicateCheck, params }, { isTransformResponse: false });
/**
* 20231215
* liaozhiyang
*
* @param params
*/
let timer;
export const duplicateCheckDelay = (params) => {
return new Promise((resove, rejected) => {
clearTimeout(timer);
timer = setTimeout(() => {
defHttp
.get({ url: Api.duplicateCheck, params }, { isTransformResponse: false })
.then((res: any) => {
resove(res as any);
})
.catch((error) => {
rejected(error);
});
}, 500);
});
};
/**
*
* @param params
*/
export const getAllRolesList = (params) => defHttp.get({ url: Api.allRolesList, params });
/**
*
* @param params
*/
export const getAllRolesListNoByTenant = (params) => defHttp.get({ url: Api.allRolesListNoByTenant, params });
/**
*
*/
export const getAllTenantList = (params) => defHttp.get({ url: Api.allTenantList, params });
/**
*
*/
export const getUserDepartList = (params) => defHttp.get({ url: Api.userDepartList, params }, { successMessageMode: 'none' });
/**
*
*/
export const getAllPostList = (params) => {
return new Promise((resolve) => {
defHttp.get({ url: Api.allPostList, params }).then((res) => {
resolve(res.records);
});
});
};
/**
*
* @param params
*/
export const getRecycleBinList = (params) => defHttp.get({ url: Api.recycleBinList, params });
/**
*
* @param params
*/
export const putRecycleBin = (params, handleSuccess) => {
return defHttp.put({ url: Api.putRecycleBin, params }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const deleteRecycleBin = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteRecycleBin, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const changePassword = (params) => {
return defHttp.put({ url: Api.changePassword, params });
};
/**
*
* @param params
*/
export const frozenBatch = (params, handleSuccess) => {
return defHttp.put({ url: Api.frozenBatch, params }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const getUserAgent = (params) => defHttp.get({ url: Api.getUserAgent, params }, { isTransformResponse: false });
/**
*
* @param params
*/
export const saveOrUpdateAgent = (params) => {
let url = params.id ? Api.agentEdit : Api.agentSave;
return defHttp.post({ url: url, params });
};
/**
* ()
* @param params
*/
export const userQuitAgent = (params) => {
return defHttp.put({ url: Api.userQuitAgent, params });
};
/**
*
* @param params
*/
export const getQuitList = (params) => {
return defHttp.get({ url: Api.getQuitList, params });
};
/**
*
* @param params
*/
export const putCancelQuit = (params, handleSuccess) => {
return defHttp.put({ url: Api.putCancelQuit, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
*/
export const getUserTenantPageList = (params) => {
return defHttp.get({ url: Api.getUserTenantPageList, params });
};
/**
*
* @param params
*/
export const updateUserTenantStatus = (params) => {
return defHttp.put({ url: Api.updateUserTenantStatus, params }, { joinParamsToUrl: true, isTransformResponse: false });
};

View File

@ -0,0 +1,557 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { getAllRolesListNoByTenant, getAllTenantList } from './user.api';
import { rules } from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
export const columns: BasicColumn[] = [
{
title: '用户账号',
dataIndex: 'username',
width: 120,
},
{
title: '用户姓名',
dataIndex: 'realname',
width: 100,
},
{
title: '头像',
dataIndex: 'avatar',
width: 120,
customRender: render.renderAvatar,
},
{
title: '性别',
dataIndex: 'sex',
width: 80,
sorter: true,
customRender: ({ text }) => {
return render.renderDict(text, 'sex');
},
},
/*{
title: '生日',
dataIndex: 'birthday',
width: 100,
},*/
{
title: '手机号',
dataIndex: 'phone',
width: 100,
},
{
title: '部门',
width: 150,
dataIndex: 'orgCodeTxt',
},
/*{
title: '负责部门',
width: 150,
dataIndex: 'departIds_dictText',
},*/
{
title: '状态',
dataIndex: 'status_dictText',
width: 80,
},
];
export const recycleColumns: BasicColumn[] = [
{
title: '用户账号',
dataIndex: 'username',
width: 100,
},
{
title: '用户姓名',
dataIndex: 'realname',
width: 100,
},
{
title: '头像',
dataIndex: 'avatar',
width: 80,
customRender: render.renderAvatar,
},
{
title: '性别',
dataIndex: 'sex',
width: 80,
sorter: true,
customRender: ({ text }) => {
return render.renderDict(text, 'sex');
},
},
];
export const searchFormSchema: FormSchema[] = [
{
label: '账号',
field: 'username',
component: 'JInput',
//colProps: { span: 6 },
},
{
label: '名字',
field: 'realname',
component: 'JInput',
//colProps: { span: 6 },
},
{
label: '性别',
field: 'sex',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
placeholder: '请选择性别',
stringToNumber: true,
},
//colProps: { span: 6 },
},
{
label: '手机号码',
field: 'phone',
component: 'Input',
//colProps: { span: 6 },
},
{
label: '用户状态',
field: 'status',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'user_status',
placeholder: '请选择状态',
stringToNumber: true,
},
//colProps: { span: 6 },
},
];
export const formSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '用户账号',
field: 'username',
component: 'Input',
dynamicDisabled: ({ values }) => {
return !!values.id;
},
dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'username', model, schema, true),
},
{
label: '登录密码',
field: 'password',
component: 'StrengthMeter',
rules: [
{
required: true,
message: '请输入登录密码',
},
/*{
pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
message: '密码由8位数字、大小写字母和特殊符号组成!',
},*/
],
},
{
label: '确认密码',
field: 'confirmPassword',
component: 'InputPassword',
dynamicRules: ({ values }) => rules.confirmPassword(values, true),
},
{
label: '用户姓名',
field: 'realname',
required: true,
component: 'Input',
},
{
label: '工号',
field: 'workNo',
required: false,
component: 'Input',
dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'work_no', model, schema, true),
},
/*{
label: '职务',
field: 'post',
required: false,
component: 'JSelectPosition',
componentProps: {
labelKey: 'name',
},
},*/
{
label: '角色',
field: 'selectedroles',
component: 'ApiSelect',
componentProps: {
mode: 'multiple',
api: getAllRolesListNoByTenant,
labelField: 'roleName',
valueField: 'id',
immediate: false,
},
},
{
label: '所属部门',
field: 'selecteddeparts',
component: 'JSelectDept',
componentProps: ({ formActionType, formModel }) => {
return {
sync: false,
checkStrictly: true,
defaultExpandLevel: 2,
onSelect: (options, values) => {
const { updateSchema } = formActionType;
//所属部门修改后更新负责部门下拉框数据
updateSchema([
{
field: 'departIds',
componentProps: { options },
},
]);
//所属部门修改后更新负责部门数据
formModel.departIds && (formModel.departIds = formModel.departIds.filter((item) => values.value.indexOf(item) > -1));
},
};
},
},
{
label: '租户',
field: 'relTenantIds',
component: 'ApiSelect',
componentProps: {
mode: 'multiple',
api: getAllTenantList,
numberToString: true,
labelField: 'name',
valueField: 'id',
immediate: false,
},
},
{
label: '身份',
field: 'userIdentity',
component: 'RadioGroup',
defaultValue: 1,
componentProps: ({ formModel }) => {
return {
options: [
{ label: '普通用户', value: 1, key: '1' },
{ label: '上级', value: 2, key: '2' },
],
onChange: () => {
formModel.userIdentity == 1 && (formModel.departIds = []);
},
};
},
},
{
label: '负责部门',
field: 'departIds',
component: 'Select',
componentProps: {
mode: 'multiple',
},
ifShow: ({ values }) => values.userIdentity == 2,
},
{
label: '头像',
field: 'avatar',
component: 'JImageUpload',
componentProps: {
fileMax: 1,
},
},
{
label: '生日',
field: 'birthday',
component: 'DatePicker',
},
{
label: '性别',
field: 'sex',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
placeholder: '请选择性别',
stringToNumber: true,
},
},
{
label: '邮箱',
field: 'email',
component: 'Input',
dynamicRules: ({ model, schema }) => {
return [
{ ...rules.duplicateCheckRule('sys_user', 'email', model, schema, true)[0], trigger: 'blur' },
{ ...rules.rule('email', false)[0], trigger: 'blur' },
];
},
},
{
label: '手机号码',
field: 'phone',
component: 'Input',
dynamicRules: ({ model, schema }) => {
return [
{ ...rules.duplicateCheckRule('sys_user', 'phone', model, schema, true)[0], trigger: 'blur' },
{ pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误', trigger: 'blur' },
];
},
},
{
label: '座机',
field: 'telephone',
component: 'Input',
rules: [{ pattern: /^0\d{2,3}-[1-9]\d{6,7}$/, message: '请输入正确的座机号码' }],
},
{
label: '工作流引擎',
field: 'activitiSync',
defaultValue: 1,
component: 'JDictSelectTag',
componentProps: {
dictCode: 'activiti_sync',
type: 'radio',
stringToNumber: true,
},
},
];
export const formPasswordSchema: FormSchema[] = [
{
label: '用户账号',
field: 'username',
component: 'Input',
componentProps: { readOnly: true },
},
{
label: '登录密码',
field: 'password',
component: 'StrengthMeter',
componentProps: {
placeholder: '请输入登录密码',
},
rules: [
{
required: true,
message: '请输入登录密码',
},
/*{
pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
message: '密码由8位数字、大小写字母和特殊符号组成!',
},*/
],
},
{
label: '确认密码',
field: 'confirmPassword',
component: 'InputPassword',
dynamicRules: ({ values }) => rules.confirmPassword(values, true),
},
];
export const formAgentSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
field: 'userName',
label: '用户名',
component: 'Input',
componentProps: {
readOnly: true,
allowClear: false,
},
},
{
field: 'agentUserName',
label: '代理人用户名',
required: true,
component: 'JSelectUser',
componentProps: {
rowKey: 'username',
labelKey: 'realname',
maxSelectCount: 10,
},
},
{
field: 'startTime',
label: '代理开始时间',
component: 'DatePicker',
required: true,
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择代理开始时间',
getPopupContainer: () => document.body,
},
},
{
field: 'endTime',
label: '代理结束时间',
component: 'DatePicker',
required: true,
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择代理结束时间',
getPopupContainer: () => document.body,
},
},
{
field: 'status',
label: '状态',
component: 'JDictSelectTag',
defaultValue: '1',
componentProps: {
dictCode: 'valid_status',
type: 'radioButton',
},
},
];
export const formQuitAgentSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
field: 'userName',
label: '用户名',
component: 'Input',
componentProps: {
readOnly: true,
allowClear: false,
},
},
{
field: 'agentUserName',
label: '交接人员',
required: true,
component: 'JSelectUser',
componentProps: {
rowKey: 'username',
labelKey: 'realname',
maxSelectCount: 1,
},
},
{
field: 'startTime',
label: '交接开始时间',
component: 'DatePicker',
required: true,
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择交接开始时间',
getPopupContainer: () => document.body,
},
},
{
field: 'endTime',
label: '交接结束时间',
component: 'DatePicker',
required: true,
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择交接结束时间',
getPopupContainer: () => document.body,
},
},
{
field: 'status',
label: '状态',
component: 'JDictSelectTag',
defaultValue: '1',
componentProps: {
dictCode: 'valid_status',
type: 'radioButton',
},
},
];
//租户用户列表
export const userTenantColumns: BasicColumn[] = [
{
title: '用户账号',
dataIndex: 'username',
width: 120,
},
{
title: '用户姓名',
dataIndex: 'realname',
width: 100,
},
{
title: '头像',
dataIndex: 'avatar',
width: 120,
customRender: render.renderAvatar,
},
{
title: '手机号',
dataIndex: 'phone',
width: 100,
},
{
title: '部门',
width: 150,
dataIndex: 'orgCodeTxt',
},
{
title: '状态',
dataIndex: 'status',
width: 80,
customRender: ({ text }) => {
if (text === '1') {
return '正常';
} else if (text === '3') {
return '审批中';
} else {
return '已拒绝';
}
},
},
];
//用户租户搜索表单
export const userTenantFormSchema: FormSchema[] = [
{
label: '账号',
field: 'username',
component: 'Input',
colProps: { span: 6 },
},
{
label: '名字',
field: 'realname',
component: 'Input',
colProps: { span: 6 },
},
{
label: '性别',
field: 'sex',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
placeholder: '请选择性别',
stringToNumber: true,
},
colProps: { span: 6 },
},
];

View File

@ -0,0 +1,54 @@
<template>
<Description @register="register" class="mt-4" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { Description, DescItem, useDescription } from '/@/components/Description/index';
const mockData = {
username: 'test',
nickName: 'VB',
age: '123',
phone: '15695909xxx',
email: '190848757@qq.com',
addr: '厦门市思明区',
sex: '男',
certy: '3504256199xxxxxxxxx',
tag: 'orange',
};
const schema: DescItem[] = [
{
field: 'username',
label: '用户名',
},
{
field: 'nickName',
label: '昵称',
render: (curVal, data) => {
return `${data.username}-${curVal}`;
},
},
{
field: 'phone',
label: '联系电话',
},
{
field: 'email',
label: '邮箱',
},
{
field: 'addr',
label: '地址',
},
];
export default defineComponent({
components: { Description },
setup() {
const [register] = useDescription({
title: 'useDescription',
data: mockData,
schema: schema,
});
return { mockData, schema, register };
},
});
</script>

View File

@ -452,9 +452,9 @@ export const tenantUserSchema: FormSchema[] = [
field: 'workNo', field: 'workNo',
label: '工号', label: '工号',
component: 'Input', component: 'Input',
dynamicRules: ({ model, schema }) => { /*dynamicRules: ({ model, schema }) => {
return [{ required: true, message: '请输入工号' }, { ...rules.duplicateCheckRule('sys_user', 'work_no', model, schema, false)[0] }]; return [{ required: true, message: '请输入工号' }, { ...rules.duplicateCheckRule('sys_user', 'work_no', model, schema, false)[0] }];
}, },*/
}, },
{ field: 'relTenantIds', label: '租户', component: 'Input',show:false }, { field: 'relTenantIds', label: '租户', component: 'Input',show:false },
{ field: 'selectedroles', label: '角色', component: 'Input',show:false }, { field: 'selectedroles', label: '角色', component: 'Input',show:false },

View File

@ -0,0 +1,42 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="修改密码" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" name="PassWordModal" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formPasswordSchema } from './user.data';
import { changePassword } from './user.api';
// Emits
const emit = defineEmits(['success', 'register']);
//
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: formPasswordSchema,
showActionButtonGroup: false,
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false });
//
await setFieldsValue({ ...data });
});
//
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//
await changePassword(values);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,45 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="用户代理" @ok="handleSubmit" destroyOnClose>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formAgentSchema } from './user.data';
import { getUserAgent, saveOrUpdateAgent } from './user.api';
// Emits
const emit = defineEmits(['success', 'register']);
//
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: formAgentSchema,
showActionButtonGroup: false,
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false });
//
const res = await getUserAgent({ userName: data.userName });
data = res.result ? res.result : data;
//
await setFieldsValue({ ...data });
});
//
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//
await saveOrUpdateAgent(values);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,160 @@
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
:title="getTitle"
:width="adaptiveWidth"
@ok="handleSubmit"
:showFooter="showFooter"
destroyOnClose
>
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { defineComponent, ref, computed, unref, useAttrs } from 'vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from './user.data';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { saveOrUpdateUser, getUserRoles, getUserDepartList, getAllRolesListNoByTenant, getAllRolesList } from './user.api';
import { useDrawerAdaptiveWidth } from '/@/hooks/jeecg/useAdaptiveWidth';
import { getTenantId } from "/@/utils/auth";
// Emits
const emit = defineEmits(['success', 'register']);
const attrs = useAttrs();
const isUpdate = ref(true);
const rowId = ref('');
const departOptions = ref([]);
//
const [registerForm, { setProps, resetFields, setFieldsValue, validate, updateSchema }] = useForm({
labelWidth: 90,
schemas: formSchema,
showActionButtonGroup: false,
});
// TODO [VUEN-527] https://www.teambition.com/task/6239beb894b358003fe93626
const showFooter = ref(true);
//
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
await resetFields();
showFooter.value = data?.showFooter ?? true;
setDrawerProps({ confirmLoading: false, showFooter: showFooter.value });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
rowId.value = data.record.id;
//
if (data.record.relTenantIds && !Array.isArray(data.record.relTenantIds)) {
data.record.relTenantIds = data.record.relTenantIds.split(',');
} else {
//issues/I56C5I
//data.record.relTenantIds = [];
}
////try catch
try {
const userRoles = await getUserRoles({ userid: data.record.id });
if (userRoles && userRoles.length > 0) {
data.record.selectedroles = userRoles;
}
} catch (error) {}
///
const userDepart = await getUserDepartList({ userId: data.record.id });
if (userDepart && userDepart.length > 0) {
data.record.selecteddeparts = userDepart;
let selectDepartKeys = Array.from(userDepart, ({ key }) => key);
data.record.selecteddeparts = selectDepartKeys.join(',');
departOptions.value = userDepart.map((item) => {
return { label: item.title, value: item.key };
});
}
///
data.record.departIds && !Array.isArray(data.record.departIds) && (data.record.departIds = data.record.departIds.split(','));
//update-begin---author:zyf Date:20211210 for------------
//update-begin---author:liusq Date:20231008 for[issues/772]------------
data.record.departIds = (!data.record.departIds || data.record.departIds == '') ? [] : data.record.departIds;
//update-end-----author:liusq Date:20231008 for[issues/772]------------
//update-begin---author:zyf Date:20211210 for------------
}
//()
data.selectedroles && (await setFieldsValue({ selectedroles: data.selectedroles }));
////
updateSchema([
{
field: 'password',
// QQYUN-8324
ifShow: !unref(isUpdate),
},
{
field: 'confirmPassword',
ifShow: !unref(isUpdate),
},
{
field: 'selectedroles',
show: !data.isRole,
},
{
field: 'departIds',
componentProps: { options: departOptions },
},
{
field: 'selecteddeparts',
show: !data?.departDisabled ?? false,
},
{
field: 'selectedroles',
show: !data?.departDisabled ?? false,
//update-begin---author:wangshuai ---date:20230424 forissues/4844------------
//
componentProps:{
api: data.tenantSaas?getAllRolesList:getAllRolesListNoByTenant
}
//update-end---author:wangshuai ---date:20230424 forissues/4844------------
},
//update-begin---author:wangshuai ---date:20230522 forissues/4935------------
{
field: 'relTenantIds',
componentProps:{
disabled: !!data.tenantSaas,
},
},
//update-end---author:wangshuai ---date:20230522 forissues/4935------------
]);
//update-begin---author:wangshuai ---date:20230522 forissues/4935------------
if(!unref(isUpdate) && data.tenantSaas){
await setFieldsValue({ relTenantIds: getTenantId().toString() })
}
//update-end---author:wangshuai ---date:20230522 forissues/4935------------
//
if (typeof data.record === 'object') {
setFieldsValue({
...data.record,
});
}
//
//update-begin-author:taoyan date:2022-5-24 for: VUEN-1117issue0523
setProps({ disabled: !showFooter.value });
//update-end-author:taoyan date:2022-5-24 for: VUEN-1117issue0523
});
//
const getTitle = computed(() => (!unref(isUpdate) ? '新增用户' : '编辑用户'));
const { adaptiveWidth } = useDrawerAdaptiveWidth();
//
async function handleSubmit() {
try {
let values = await validate();
setDrawerProps({ confirmLoading: true });
values.userIdentity === 1 && (values.departIds = '');
let isUpdateVal = unref(isUpdate);
//
await saveOrUpdateUser(values, isUpdateVal);
//
closeDrawer();
//
emit('success',{isUpdateVal ,values});
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,81 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="离职交接" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup name="user-quit-agent-modal">
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formQuitAgentSchema } from './user.data';
import { getUserAgent, userQuitAgent } from './user.api';
import dayjs from 'dayjs';
// Emits
const emit = defineEmits(['success', 'register']);
//
const [registerForm, { resetFields, setFieldsValue, validate, clearValidate, updateSchema }] = useForm({
schemas: formQuitAgentSchema,
showActionButtonGroup: false,
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: true });
let userId = data.userId;
//
const res = await getUserAgent({ userName: data.userName });
data = res.result ? res.result : data;
let date = new Date();
if (!data.startTime) {
data.startTime = dayjs(date).format('YYYY-MM-DD HH:mm:ss');
}
if (!data.endTime) {
data.endTime = getYear(date);
}
//update-begin---author:wangshuai ---date:20230703 forQQYUN-56855------------
await updateSchema(
[{
field:'agentUserName',
componentProps:{
excludeUserIdList:[userId]
}
}]
)
//update-end---author:wangshuai ---date:20230703 forQQYUN-56855------------
//
await setFieldsValue({ ...data });
setModalProps({ confirmLoading: false });
});
//
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//
await userQuitAgent(values);
//
closeModal();
//
emit('success',values.userName);
} finally {
setModalProps({ confirmLoading: false });
}
}
/**
* 获取后30年
*/
function getYear(date) {
//update-begin---author:wangshuai ---date:20221207 for[QQYUN-3285] ------------
//
let y = date.getFullYear() + 30;
let m = dayjs(date).format('MM');
let d = dayjs(date).format('DD');
let hour = dayjs(date).format('HH:mm:ss');
console.log('年月日', y + '-' + m + '-' + d);
return dayjs(y + '-' + m + '-' + d + ' ' + hour).format('YYYY-MM-DD HH:mm:ss');
//update-end---author:wangshuai ---date:20221207 for[QQYUN-3285] --------------
}
</script>

View File

@ -0,0 +1,110 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="离职人员信息" :showOkBtn="false" width="1000px" destroyOnClose>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleRevert">
<Icon icon="ant-design:redo-outlined"></Icon>
批量取消
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="ant-design:down-outlined"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts" setup name="user-quit-modal">
import { ref, toRaw, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { recycleColumns } from './user.data';
import { getQuitList, putCancelQuit, deleteRecycleBin } from './user.api';
import { useMessage } from '/@/hooks/web/useMessage';
import { useListPage } from '/@/hooks/system/useListPage';
import { Modal } from 'ant-design-vue';
import { defHttp } from '/@/utils/http/axios';
const { createConfirm } = useMessage();
// Emits
const emit = defineEmits(['success', 'register']);
const checkedKeys = ref<Array<string | number>>([]);
const [registerModal] = useModalInner(() => {
checkedKeys.value = [];
});
//table
const { prefixCls, tableContext } = useListPage({
tableProps: {
api: getQuitList,
columns: recycleColumns,
rowKey: 'id',
canResize: false,
useSearchForm: false,
actionColumn: {
width: 120,
},
},
});
//table
const [registerTable, { reload }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
/**
* 取消离职事件
* @param record
*/
async function handleCancelQuit(record) {
await putCancelQuit({ userIds: record.id, usernames: record.username }, reload);
emit('success');
}
/**
* 批量取消离职事件
*/
function batchHandleRevert() {
Modal.confirm({
title: '取消离职',
content: '取消离职交接人也会清空',
okText: '确认',
cancelText: '取消',
onOk: () => {
let rowValue = selectedRows.value;
let rowData: any = [];
for (const value of rowValue) {
rowData.push(value.username);
}
handleCancelQuit({ id: toRaw(unref(selectedRowKeys)).join(','), username: rowData.join(',') });
},
});
}
//
function getTableAction(record) {
return [
{
label: '取消离职',
icon: 'ant-design:redo-outlined',
popConfirm: {
title: '是否取消离职,取消离职交接人也会清空',
confirm: handleCancelQuit.bind(null, record),
},
},
];
}
</script>
<style scoped lang="less">
:deep(.ant-popover-inner-content){
width: 185px !important;
}
</style>

View File

@ -0,0 +1,138 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="用户回收站" :showOkBtn="false" width="1000px" destroyOnClose>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-dropdown v-if="checkedKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
批量删除
</a-menu-item>
<a-menu-item key="1" @click="batchHandleRevert">
<Icon icon="ant-design:redo-outlined"></Icon>
批量还原
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="ant-design:down-outlined"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction :actions="getTableAction(record)" />
</template>
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, toRaw, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { recycleColumns } from './user.data';
import { getRecycleBinList, putRecycleBin, deleteRecycleBin } from './user.api';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
// Emits
const emit = defineEmits(['success', 'register']);
const checkedKeys = ref<Array<string | number>>([]);
const [registerModal] = useModalInner(() => {
checkedKeys.value = [];
});
//table
const [registerTable, { reload }] = useTable({
api: getRecycleBinList,
columns: recycleColumns,
rowKey: 'id',
striped: true,
useSearchForm: false,
showTableSetting: false,
clickToRowSelect: false,
bordered: true,
showIndexColumn: false,
pagination: true,
tableSetting: { fullScreen: true },
canResize: false,
actionColumn: {
width: 150,
title: '操作',
dataIndex: 'action',
// slots: { customRender: 'action' },
fixed: undefined,
},
});
/**
* 选择列配置
*/
const rowSelection = {
type: 'checkbox',
columnWidth: 50,
selectedRowKeys: checkedKeys,
onChange: onSelectChange,
};
/**
* 选择事件
*/
function onSelectChange(selectedRowKeys: (string | number)[]) {
checkedKeys.value = selectedRowKeys;
}
/**
* 还原事件
*/
async function handleRevert(record) {
await putRecycleBin({ userIds: record.id }, reload);
emit('success');
}
/**
* 批量还原事件
*/
function batchHandleRevert() {
handleRevert({ id: toRaw(unref(checkedKeys)).join(',') });
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteRecycleBin({ userIds: record.id }, reload);
}
/**
* 批量删除事件
*/
function batchHandleDelete() {
createConfirm({
iconType: 'warning',
title: '删除',
content: '确定要永久删除吗?删除后将不可恢复!',
onOk: () => handleDelete({ id: toRaw(unref(checkedKeys)).join(',') }),
onCancel() {},
});
}
//
function getTableAction(record) {
return [
{
label: '取回',
icon: 'ant-design:redo-outlined',
popConfirm: {
title: '是否确认还原',
confirm: handleRevert.bind(null, record),
},
},
{
label: '彻底删除',
icon: 'ant-design:scissor-outlined',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
];
}
</script>

View File

@ -0,0 +1,299 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls" :disabled="isDisabledAuth('system:user:export')"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-button type="primary" @click="openModal(true, {})" preIcon="ant-design:hdd-outlined"> 回收站</a-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
<a-menu-item key="2" @click="batchFrozen(2)">
<Icon icon="ant-design:lock-outlined"></Icon>
冻结
</a-menu-item>
<a-menu-item key="3" @click="batchFrozen(1)">
<Icon icon="ant-design:unlock-outlined"></Icon>
解冻
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
</BasicTable>
<!--用户抽屉-->
<UserDrawer @register="registerDrawer" @success="handleSuccess" />
<!--修改密码-->
<PasswordModal @register="registerPasswordModal" @success="reload" />
<!--用户代理-->
<UserAgentModal @register="registerAgentModal" @success="reload" />
<!--回收站-->
<UserRecycleBinModal @register="registerModal" @success="reload" />
<!-- 离职受理人弹窗 -->
<UserQuitAgentModal @register="registerQuitAgentModal" @success="reload" />
<!-- 离职人员列弹窗 -->
<UserQuitModal @register="registerQuitModal" @success="reload" />
</div>
</template>
<script lang="ts" name="system-user" setup>
//ts
import { ref, computed, unref } from 'vue';
import { BasicTable, TableAction, ActionItem } from '/@/components/Table';
import UserDrawer from './UserDrawer.vue';
import UserRecycleBinModal from './UserRecycleBinModal.vue';
import PasswordModal from './PasswordModal.vue';
import UserAgentModal from './UserAgentModal.vue';
import JThirdAppButton from '/@/components/jeecg/thirdApp/JThirdAppButton.vue';
import UserQuitAgentModal from './UserQuitAgentModal.vue';
import UserQuitModal from './UserQuitModal.vue';
import { useDrawer } from '/@/components/Drawer';
import { useListPage } from '/@/hooks/system/useListPage';
import { useModal } from '/@/components/Modal';
import { useMessage } from '/@/hooks/web/useMessage';
import { columns, searchFormSchema } from './user.data';
import { listNoCareTenant, deleteUser, batchDeleteUser, getImportUrl, getExportUrl, frozenBatch } from './user.api';
import {usePermission} from "/@/hooks/web/usePermission";
const { createMessage, createConfirm } = useMessage();
const { isDisabledAuth } = usePermission();
//drawer
const [registerDrawer, { openDrawer }] = useDrawer();
//model
const [registerModal, { openModal }] = useModal();
//model
const [registerPasswordModal, { openModal: openPasswordModal }] = useModal();
//model
const [registerAgentModal, { openModal: openAgentModal }] = useModal();
//model
const [registerQuitAgentModal, { openModal: openQuitAgentModal }] = useModal();
//model
const [registerQuitModal, { openModal: openQuitModal }] = useModal();
//
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
designScope: 'user-list',
tableProps: {
title: '用户列表',
api: listNoCareTenant,
columns: columns,
size: 'small',
formConfig: {
// labelWidth: 200,
schemas: searchFormSchema,
},
actionColumn: {
width: 120,
},
beforeFetch: (params) => {
return Object.assign({ column: 'createTime', order: 'desc' }, params);
},
},
exportConfig: {
name: '用户列表',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
},
});
//table
const [registerTable, { reload, updateTableDataRecord }, { rowSelection, selectedRows, selectedRowKeys }] = tableContext;
/**
* 新增事件
*/
function handleCreate() {
openDrawer(true, {
isUpdate: false,
showFooter: true,
tenantSaas: false,
});
}
/**
* 编辑事件
*/
async function handleEdit(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
showFooter: true,
tenantSaas: false,
});
}
/**
* 详情
*/
async function handleDetail(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
showFooter: false,
tenantSaas: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
if ('admin' == record.username) {
createMessage.warning('管理员账号不允许此操作!');
return;
}
await deleteUser({ id: record.id }, reload);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
let hasAdmin = unref(selectedRows).filter((item) => item.username == 'admin');
if (unref(hasAdmin).length > 0) {
createMessage.warning('管理员账号不允许此操作!');
return;
}
await batchDeleteUser({ ids: selectedRowKeys.value }, () => {
selectedRowKeys.value = [];
reload();
});
}
/**
* 成功回调
*/
function handleSuccess() {
reload();
}
/**
* 打开修改密码弹窗
*/
function handleChangePassword(username) {
openPasswordModal(true, { username });
}
/**
* 打开代理人弹窗
*/
function handleAgentSettings(userName) {
openAgentModal(true, { userName });
}
/**
* 冻结解冻
*/
async function handleFrozen(record, status) {
if ('admin' == record.username) {
createMessage.warning('管理员账号不允许此操作!');
return;
}
await frozenBatch({ ids: record.id, status: status }, reload);
}
/**
* 批量冻结解冻
*/
function batchFrozen(status) {
let hasAdmin = selectedRows.value.filter((item) => item.username == 'admin');
if (unref(hasAdmin).length > 0) {
createMessage.warning('管理员账号不允许此操作!');
return;
}
createConfirm({
iconType: 'warning',
title: '确认操作',
content: '是否' + (status == 1 ? '解冻' : '冻结') + '选中账号?',
onOk: async () => {
await frozenBatch({ ids: unref(selectedRowKeys).join(','), status: status }, reload);
},
});
}
/**
*同步钉钉和微信回调
*/
function onSyncFinally({ isToLocal }) {
//
if (isToLocal) {
reload();
}
}
/**
* 操作栏
*/
function getTableAction(record): ActionItem[] {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
// ifShow: () => hasPermission('system:user:edit'),
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record): ActionItem[] {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '密码',
//auth: 'user:changepwd',
onClick: handleChangePassword.bind(null, record.username),
},
{
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
{
label: '冻结',
ifShow: record.status == 1,
popConfirm: {
title: '确定冻结吗?',
confirm: handleFrozen.bind(null, record, 2),
},
},
{
label: '解冻',
ifShow: record.status == 2,
popConfirm: {
title: '确定解冻吗?',
confirm: handleFrozen.bind(null, record, 1),
},
},
{
label: '代理人',
onClick: handleAgentSettings.bind(null, record.username),
},
];
}
/**
* 离职
* @param userName
*/
function handleQuit(userName) {
//
openQuitAgentModal(true, { userName });
}
</script>
<style scoped></style>

View File

@ -0,0 +1,242 @@
import { defHttp } from '/@/utils/http/axios';
import { Modal } from 'ant-design-vue';
enum Api {
listNoCareTenant = '/sys/user/listAll',
list = '/sys/user/list',
save = '/sys/user/add',
edit = '/sys/user/edit',
agentSave = '/sys/sysUserAgent/add',
agentEdit = '/sys/sysUserAgent/edit',
getUserRole = '/sys/user/queryUserRole',
duplicateCheck = '/sys/duplicate/check',
deleteUser = '/sys/user/delete',
deleteBatch = '/sys/user/deleteBatch',
importExcel = '/sys/user/importExcel',
exportXls = '/sys/user/exportXls',
recycleBinList = '/sys/user/recycleBin',
putRecycleBin = '/sys/user/putRecycleBin',
deleteRecycleBin = '/sys/user/deleteRecycleBin',
allRolesList = '/sys/role/queryall',
allRolesListNoByTenant = '/sys/role/queryallNoByTenant',
allTenantList = '/sys/tenant/queryList',
allPostList = '/sys/position/list',
userDepartList = '/sys/user/userDepartList',
changePassword = '/sys/user/changePassword',
frozenBatch = '/sys/user/frozenBatch',
getUserAgent = '/sys/sysUserAgent/queryByUserName',
userQuitAgent = '/sys/user/userQuitAgent',
getQuitList = '/sys/user/getQuitList',
putCancelQuit = '/sys/user/putCancelQuit',
updateUserTenantStatus='/sys/tenant/updateUserTenantStatus',
getUserTenantPageList='/sys/tenant/getUserTenantPageList',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
* ()
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* ()
* @param params
*/
export const listNoCareTenant = (params) => defHttp.get({ url: Api.listNoCareTenant, params });
/**
*
* @param params
*/
export const getUserRoles = (params) => defHttp.get({ url: Api.getUserRole, params }, { errorMessageMode: 'none' });
/**
*
*/
export const deleteUser = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteUser, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const batchDeleteUser = (params, handleSuccess) => {
Modal.confirm({
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
*
* @param params
*/
export const saveOrUpdateUser = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
/**
*
* @param params
*/
export const duplicateCheck = (params) => defHttp.get({ url: Api.duplicateCheck, params }, { isTransformResponse: false });
/**
* 20231215
* liaozhiyang
*
* @param params
*/
let timer;
export const duplicateCheckDelay = (params) => {
return new Promise((resove, rejected) => {
clearTimeout(timer);
timer = setTimeout(() => {
defHttp
.get({ url: Api.duplicateCheck, params }, { isTransformResponse: false })
.then((res: any) => {
resove(res as any);
})
.catch((error) => {
rejected(error);
});
}, 500);
});
};
/**
*
* @param params
*/
export const getAllRolesList = (params) => defHttp.get({ url: Api.allRolesList, params });
/**
*
* @param params
*/
export const getAllRolesListNoByTenant = (params) => defHttp.get({ url: Api.allRolesListNoByTenant, params });
/**
*
*/
export const getAllTenantList = (params) => defHttp.get({ url: Api.allTenantList, params });
/**
*
*/
export const getUserDepartList = (params) => defHttp.get({ url: Api.userDepartList, params }, { successMessageMode: 'none' });
/**
*
*/
export const getAllPostList = (params) => {
return new Promise((resolve) => {
defHttp.get({ url: Api.allPostList, params }).then((res) => {
resolve(res.records);
});
});
};
/**
*
* @param params
*/
export const getRecycleBinList = (params) => defHttp.get({ url: Api.recycleBinList, params });
/**
*
* @param params
*/
export const putRecycleBin = (params, handleSuccess) => {
return defHttp.put({ url: Api.putRecycleBin, params }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const deleteRecycleBin = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteRecycleBin, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const changePassword = (params) => {
return defHttp.put({ url: Api.changePassword, params });
};
/**
*
* @param params
*/
export const frozenBatch = (params, handleSuccess) => {
return defHttp.put({ url: Api.frozenBatch, params }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const getUserAgent = (params) => defHttp.get({ url: Api.getUserAgent, params }, { isTransformResponse: false });
/**
*
* @param params
*/
export const saveOrUpdateAgent = (params) => {
let url = params.id ? Api.agentEdit : Api.agentSave;
return defHttp.post({ url: url, params });
};
/**
* ()
* @param params
*/
export const userQuitAgent = (params) => {
return defHttp.put({ url: Api.userQuitAgent, params });
};
/**
*
* @param params
*/
export const getQuitList = (params) => {
return defHttp.get({ url: Api.getQuitList, params });
};
/**
*
* @param params
*/
export const putCancelQuit = (params, handleSuccess) => {
return defHttp.put({ url: Api.putCancelQuit, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
*/
export const getUserTenantPageList = (params) => {
return defHttp.get({ url: Api.getUserTenantPageList, params });
};
/**
*
* @param params
*/
export const updateUserTenantStatus = (params) => {
return defHttp.put({ url: Api.updateUserTenantStatus, params }, { joinParamsToUrl: true, isTransformResponse: false });
};

View File

@ -0,0 +1,557 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { getAllRolesListNoByTenant, getAllTenantList } from './user.api';
import { rules } from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
export const columns: BasicColumn[] = [
{
title: '用户账号',
dataIndex: 'username',
width: 120,
},
{
title: '用户姓名',
dataIndex: 'realname',
width: 100,
},
{
title: '头像',
dataIndex: 'avatar',
width: 120,
customRender: render.renderAvatar,
},
{
title: '性别',
dataIndex: 'sex',
width: 80,
sorter: true,
customRender: ({ text }) => {
return render.renderDict(text, 'sex');
},
},
/*{
title: '生日',
dataIndex: 'birthday',
width: 100,
},*/
{
title: '手机号',
dataIndex: 'phone',
width: 100,
},
{
title: '部门',
width: 150,
dataIndex: 'orgCodeTxt',
},
/*{
title: '负责部门',
width: 150,
dataIndex: 'departIds_dictText',
},*/
{
title: '状态',
dataIndex: 'status_dictText',
width: 80,
},
];
export const recycleColumns: BasicColumn[] = [
{
title: '用户账号',
dataIndex: 'username',
width: 100,
},
{
title: '用户姓名',
dataIndex: 'realname',
width: 100,
},
{
title: '头像',
dataIndex: 'avatar',
width: 80,
customRender: render.renderAvatar,
},
{
title: '性别',
dataIndex: 'sex',
width: 80,
sorter: true,
customRender: ({ text }) => {
return render.renderDict(text, 'sex');
},
},
];
export const searchFormSchema: FormSchema[] = [
{
label: '账号',
field: 'username',
component: 'JInput',
//colProps: { span: 6 },
},
{
label: '名字',
field: 'realname',
component: 'JInput',
//colProps: { span: 6 },
},
{
label: '性别',
field: 'sex',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
placeholder: '请选择性别',
stringToNumber: true,
},
//colProps: { span: 6 },
},
{
label: '手机号码',
field: 'phone',
component: 'Input',
//colProps: { span: 6 },
},
{
label: '用户状态',
field: 'status',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'user_status',
placeholder: '请选择状态',
stringToNumber: true,
},
//colProps: { span: 6 },
},
];
export const formSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '用户账号',
field: 'username',
component: 'Input',
dynamicDisabled: ({ values }) => {
return !!values.id;
},
dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'username', model, schema, true),
},
{
label: '登录密码',
field: 'password',
component: 'StrengthMeter',
rules: [
{
required: true,
message: '请输入登录密码',
},
/*{
pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
message: '密码由8位数字、大小写字母和特殊符号组成!',
},*/
],
},
{
label: '确认密码',
field: 'confirmPassword',
component: 'InputPassword',
dynamicRules: ({ values }) => rules.confirmPassword(values, true),
},
{
label: '用户姓名',
field: 'realname',
required: true,
component: 'Input',
},
{
label: '工号',
field: 'workNo',
required: false,
component: 'Input',
dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'work_no', model, schema, true),
},
/*{
label: '职务',
field: 'post',
required: false,
component: 'JSelectPosition',
componentProps: {
labelKey: 'name',
},
},*/
{
label: '角色',
field: 'selectedroles',
component: 'ApiSelect',
componentProps: {
mode: 'multiple',
api: getAllRolesListNoByTenant,
labelField: 'roleName',
valueField: 'id',
immediate: false,
},
},
{
label: '所属部门',
field: 'selecteddeparts',
component: 'JSelectDept',
componentProps: ({ formActionType, formModel }) => {
return {
sync: false,
checkStrictly: true,
defaultExpandLevel: 2,
onSelect: (options, values) => {
const { updateSchema } = formActionType;
//所属部门修改后更新负责部门下拉框数据
updateSchema([
{
field: 'departIds',
componentProps: { options },
},
]);
//所属部门修改后更新负责部门数据
formModel.departIds && (formModel.departIds = formModel.departIds.filter((item) => values.value.indexOf(item) > -1));
},
};
},
},
{
label: '租户',
field: 'relTenantIds',
component: 'ApiSelect',
componentProps: {
mode: 'multiple',
api: getAllTenantList,
numberToString: true,
labelField: 'name',
valueField: 'id',
immediate: false,
},
},
{
label: '身份',
field: 'userIdentity',
component: 'RadioGroup',
defaultValue: 1,
componentProps: ({ formModel }) => {
return {
options: [
{ label: '普通用户', value: 1, key: '1' },
{ label: '上级', value: 2, key: '2' },
],
onChange: () => {
formModel.userIdentity == 1 && (formModel.departIds = []);
},
};
},
},
{
label: '负责部门',
field: 'departIds',
component: 'Select',
componentProps: {
mode: 'multiple',
},
ifShow: ({ values }) => values.userIdentity == 2,
},
{
label: '头像',
field: 'avatar',
component: 'JImageUpload',
componentProps: {
fileMax: 1,
},
},
{
label: '生日',
field: 'birthday',
component: 'DatePicker',
},
{
label: '性别',
field: 'sex',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
placeholder: '请选择性别',
stringToNumber: true,
},
},
{
label: '邮箱',
field: 'email',
component: 'Input',
dynamicRules: ({ model, schema }) => {
return [
{ ...rules.duplicateCheckRule('sys_user', 'email', model, schema, true)[0], trigger: 'blur' },
{ ...rules.rule('email', false)[0], trigger: 'blur' },
];
},
},
{
label: '手机号码',
field: 'phone',
component: 'Input',
dynamicRules: ({ model, schema }) => {
return [
{ ...rules.duplicateCheckRule('sys_user', 'phone', model, schema, true)[0], trigger: 'blur' },
{ pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误', trigger: 'blur' },
];
},
},
{
label: '座机',
field: 'telephone',
component: 'Input',
rules: [{ pattern: /^0\d{2,3}-[1-9]\d{6,7}$/, message: '请输入正确的座机号码' }],
},
{
label: '工作流引擎',
field: 'activitiSync',
defaultValue: 1,
component: 'JDictSelectTag',
componentProps: {
dictCode: 'activiti_sync',
type: 'radio',
stringToNumber: true,
},
},
];
export const formPasswordSchema: FormSchema[] = [
{
label: '用户账号',
field: 'username',
component: 'Input',
componentProps: { readOnly: true },
},
{
label: '登录密码',
field: 'password',
component: 'StrengthMeter',
componentProps: {
placeholder: '请输入登录密码',
},
rules: [
{
required: true,
message: '请输入登录密码',
},
/*{
pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
message: '密码由8位数字、大小写字母和特殊符号组成!',
},*/
],
},
{
label: '确认密码',
field: 'confirmPassword',
component: 'InputPassword',
dynamicRules: ({ values }) => rules.confirmPassword(values, true),
},
];
export const formAgentSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
field: 'userName',
label: '用户名',
component: 'Input',
componentProps: {
readOnly: true,
allowClear: false,
},
},
{
field: 'agentUserName',
label: '代理人用户名',
required: true,
component: 'JSelectUser',
componentProps: {
rowKey: 'username',
labelKey: 'realname',
maxSelectCount: 10,
},
},
{
field: 'startTime',
label: '代理开始时间',
component: 'DatePicker',
required: true,
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择代理开始时间',
getPopupContainer: () => document.body,
},
},
{
field: 'endTime',
label: '代理结束时间',
component: 'DatePicker',
required: true,
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择代理结束时间',
getPopupContainer: () => document.body,
},
},
{
field: 'status',
label: '状态',
component: 'JDictSelectTag',
defaultValue: '1',
componentProps: {
dictCode: 'valid_status',
type: 'radioButton',
},
},
];
export const formQuitAgentSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
field: 'userName',
label: '用户名',
component: 'Input',
componentProps: {
readOnly: true,
allowClear: false,
},
},
{
field: 'agentUserName',
label: '交接人员',
required: true,
component: 'JSelectUser',
componentProps: {
rowKey: 'username',
labelKey: 'realname',
maxSelectCount: 1,
},
},
{
field: 'startTime',
label: '交接开始时间',
component: 'DatePicker',
required: true,
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择交接开始时间',
getPopupContainer: () => document.body,
},
},
{
field: 'endTime',
label: '交接结束时间',
component: 'DatePicker',
required: true,
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择交接结束时间',
getPopupContainer: () => document.body,
},
},
{
field: 'status',
label: '状态',
component: 'JDictSelectTag',
defaultValue: '1',
componentProps: {
dictCode: 'valid_status',
type: 'radioButton',
},
},
];
//租户用户列表
export const userTenantColumns: BasicColumn[] = [
{
title: '用户账号',
dataIndex: 'username',
width: 120,
},
{
title: '用户姓名',
dataIndex: 'realname',
width: 100,
},
{
title: '头像',
dataIndex: 'avatar',
width: 120,
customRender: render.renderAvatar,
},
{
title: '手机号',
dataIndex: 'phone',
width: 100,
},
{
title: '部门',
width: 150,
dataIndex: 'orgCodeTxt',
},
{
title: '状态',
dataIndex: 'status',
width: 80,
customRender: ({ text }) => {
if (text === '1') {
return '正常';
} else if (text === '3') {
return '审批中';
} else {
return '已拒绝';
}
},
},
];
//用户租户搜索表单
export const userTenantFormSchema: FormSchema[] = [
{
label: '账号',
field: 'username',
component: 'Input',
colProps: { span: 6 },
},
{
label: '名字',
field: 'realname',
component: 'Input',
colProps: { span: 6 },
},
{
label: '性别',
field: 'sex',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
placeholder: '请选择性别',
stringToNumber: true,
},
colProps: { span: 6 },
},
];

View File

@ -0,0 +1,54 @@
<template>
<Description @register="register" class="mt-4" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { Description, DescItem, useDescription } from '/@/components/Description/index';
const mockData = {
username: 'test',
nickName: 'VB',
age: '123',
phone: '15695909xxx',
email: '190848757@qq.com',
addr: '厦门市思明区',
sex: '男',
certy: '3504256199xxxxxxxxx',
tag: 'orange',
};
const schema: DescItem[] = [
{
field: 'username',
label: '用户名',
},
{
field: 'nickName',
label: '昵称',
render: (curVal, data) => {
return `${data.username}-${curVal}`;
},
},
{
field: 'phone',
label: '联系电话',
},
{
field: 'email',
label: '邮箱',
},
{
field: 'addr',
label: '地址',
},
];
export default defineComponent({
components: { Description },
setup() {
const [register] = useDescription({
title: 'useDescription',
data: mockData,
schema: schema,
});
return { mockData, schema, register };
},
});
</script>

View File

@ -29,11 +29,11 @@ export const columns: BasicColumn[] = [
return render.renderDict(text, 'sex'); return render.renderDict(text, 'sex');
}, },
}, },
{ /*{
title: '生日', title: '生日',
dataIndex: 'birthday', dataIndex: 'birthday',
width: 100, width: 100,
}, },*/
{ {
title: '手机号', title: '手机号',
dataIndex: 'phone', dataIndex: 'phone',
@ -44,11 +44,11 @@ export const columns: BasicColumn[] = [
width: 150, width: 150,
dataIndex: 'orgCodeTxt', dataIndex: 'orgCodeTxt',
}, },
{ /*{
title: '负责部门', title: '负责部门',
width: 150, width: 150,
dataIndex: 'departIds_dictText', dataIndex: 'departIds_dictText',
}, },*/
{ {
title: '状态', title: '状态',
dataIndex: 'status_dictText', dataIndex: 'status_dictText',
@ -173,11 +173,11 @@ export const formSchema: FormSchema[] = [
{ {
label: '工号', label: '工号',
field: 'workNo', field: 'workNo',
required: true, required: false,
component: 'Input', component: 'Input',
dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'work_no', model, schema, true), dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'work_no', model, schema, true),
}, },
{ /*{
label: '职务', label: '职务',
field: 'post', field: 'post',
required: false, required: false,
@ -185,7 +185,7 @@ export const formSchema: FormSchema[] = [
componentProps: { componentProps: {
labelKey: 'name', labelKey: 'name',
}, },
}, },*/
{ {
label: '角色', label: '角色',
field: 'selectedroles', field: 'selectedroles',

View File

@ -3,15 +3,30 @@ import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage(); const { createConfirm } = useMessage();
enum Api { enum Api {
list = '/yx/yxHistoryMajorEnroll/list', list = '/yx/yxHistoryMajorEnroll/list',
save='/yx/yxHistoryMajorEnroll/add', getData = '/yx/yxHistoryMajorEnroll/list',
edit='/yx/yxHistoryMajorEnroll/edit', // 模拟保存单行数据(即时保存)
saveRow = '/yx/yxHistoryMajorEnroll/edit',
// 模拟保存整个表格的数据
saveAll = '/yx/yxHistoryMajorEnroll/saveBatch',
save = '/yx/yxHistoryMajorEnroll/add',
edit = '/yx/yxHistoryMajorEnroll/edit',
deleteOne = '/yx/yxHistoryMajorEnroll/delete', deleteOne = '/yx/yxHistoryMajorEnroll/delete',
deleteBatch = '/yx/yxHistoryMajorEnroll/deleteBatch', deleteBatch = '/yx/yxHistoryMajorEnroll/deleteBatch',
importExcel = '/yx/yxHistoryMajorEnroll/importExcel', importExcel = '/yx/yxHistoryMajorEnroll/importExcel',
exportXls = '/yx/yxHistoryMajorEnroll/exportXls', exportXls = '/yx/yxHistoryMajorEnroll/exportXls',
// exportXls = '/yx/yxHistoryMajorEnroll/exportXlsBySchoolMajor',
renewControlLine = '/yx/yxHistoryMajorEnroll/renewControlLine'
} }
export const getData = Api.getData;
export const saveRow = Api.saveRow;
export const saveAll = Api.saveAll;
export const deleteBatch = Api.deleteBatch;
export const renewControlLine = Api.renewControlLine;
/** /**
* api * api
* @param params * @param params

View File

@ -2,6 +2,154 @@ import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table'; import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator'; import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils'; import { render } from '/@/utils/common/renderUtils';
import {JVxeColumn, JVxeTypes} from '/@/components/jeecg/JVxeTable/types';
import { ref } from 'vue';
export const columnsN = ref<JVxeColumn[]>([
/*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/
{
title: '学校代码',
key: 'schoolCode',
width: 100,
type: JVxeTypes.input,
},
{
title: '院校代码',
key: 'institutionCode',
width: 100,
type: JVxeTypes.input,
},
{
title: '学校名称',
key: 'schoolName',
width: 150,
type: JVxeTypes.input,
},
{
title: '专业代码',
key: 'majorCode',
width: 100,
type: JVxeTypes.input,
},
{
title: '专业名称',
key: 'majorName',
width: 200,
type: JVxeTypes.textarea,
},
{
title: '招生代码',
key: 'enrollmentCode',
width: 100,
type: JVxeTypes.input,
},
{
title: '专业类型',
key: 'majorType',
width: 130,
type: JVxeTypes.input,
},
{
title: '专业类别子级',
key: 'majorTypeChild',
width: 130,
type: JVxeTypes.input,
},
{
title: '主考科目',
key: 'mainSubjects',
width: 130,
type: JVxeTypes.input,
},
{
title: '年份',
key: 'year',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '科类(文科/理科)',
key: 'category',
width: 100,
type: JVxeTypes.input,
},
{
title: '批次',
key: 'batch',
width: 100,
type: JVxeTypes.input,
},
{
title: '录取方式(文*x+专*y)',
key: 'rulesEnrollProbability',
width: 150,
type: JVxeTypes.input,
},
{
title: '录取概率计算规则运算符',
key: 'probabilityOperator',
width: 150,
type: JVxeTypes.input,
},
{
title: '省控线',
key: 'controlLine',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '录取线',
key: 'admissionLine',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '招生人数',
key: 'enrollNum',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '实际投档人数',
key: 'actualPitcherNum',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '录取数',
key: 'admissionNum',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '一志愿录取数',
key: 'oneVolunteerAdmissionNum',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '最低分数差',
key: 'scoreLineDifference',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '学费',
key: 'tuition',
width: 200,
type: JVxeTypes.input,
},
{
title: '备注',
key: 'detail',
width: 200,
type: JVxeTypes.textarea,
}
]);
//列表数据 //列表数据
export const columns: BasicColumn[] = [ export const columns: BasicColumn[] = [
{ {

View File

@ -59,8 +59,8 @@
<a-col :span="12"> <a-col :span="12">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button> <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button> <a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="renewControlLine" style="margin-left: 8px">刷新省控线</a-button> <!-- <a-button type="primary" preIcon="ant-design:reload-outlined" @click="handleRenewControlLine" style="margin-left: 8px">刷新省控线</a-button>-->
<a-button type="primary" preIcon="ant-design:export-outlined" @click="exportXls" style="margin: 8px">导出</a-button> <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls" style="margin: 8px">导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls" style="margin-left: 8px">导入</j-upload-button> <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls" style="margin-left: 8px">导入</j-upload-button>
</a-col> </a-col>
</a-row> </a-row>
@ -94,7 +94,9 @@ import {defHttp} from '/@/utils/http/axios';
import {JVxeColumn, JVxeTypes} from '/@/components/jeecg/JVxeTable/types'; import {JVxeColumn, JVxeTypes} from '/@/components/jeecg/JVxeTable/types';
import {useMessage} from '/@/hooks/web/useMessage'; import {useMessage} from '/@/hooks/web/useMessage';
import {useListPage} from "@/hooks/system/useListPage"; import {useListPage} from "@/hooks/system/useListPage";
import {getExportUrl, getImportUrl, list} from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api";
import {columnsN } from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.data";
import {getData,saveRow,saveAll,deleteBatch,getExportUrl,getImportUrl,renewControlLine} from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api";
import {XLSX_FILE_SUFFIX, XLSX_MIME_TYPE} from "@/hooks/system/useMethods"; import {XLSX_FILE_SUFFIX, XLSX_MIME_TYPE} from "@/hooks/system/useMethods";
const { createMessage, createConfirm, createSuccessModal, createInfoModal, createErrorModal, createWarningModal, notification } = useMessage(); const { createMessage, createConfirm, createSuccessModal, createInfoModal, createErrorModal, createWarningModal, notification } = useMessage();
const labelCol = reactive({ const labelCol = reactive({
@ -119,6 +121,7 @@ const queryParam = reactive({
majorType: '',// majorType: '',//
category: '',// category: '',//
year: '',// year: '',//
batch:'',//
}) })
// //
const pagination = reactive({ const pagination = reactive({
@ -136,148 +139,7 @@ const selectedRows = ref<Recordable[]>([]);
// //
const dataSource = ref<Recordable[]>([]); const dataSource = ref<Recordable[]>([]);
// //
const columns = ref<JVxeColumn[]>([ const columns = columnsN;
/*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/
{
title: '学校代码',
key: 'schoolCode',
width: 100,
type: JVxeTypes.input,
},
{
title: '院校代码',
key: 'institutionCode',
width: 100,
type: JVxeTypes.input,
},
{
title: '学校名称',
key: 'schoolName',
width: 150,
type: JVxeTypes.input,
},
{
title: '专业代码',
key: 'majorCode',
width: 100,
type: JVxeTypes.input,
},
{
title: '专业名称',
key: 'majorName',
width: 200,
type: JVxeTypes.textarea,
},
{
title: '招生代码',
key: 'enrollmentCode',
width: 100,
type: JVxeTypes.input,
},
{
title: '专业类型',
key: 'majorType',
width: 130,
type: JVxeTypes.input,
},
{
title: '专业类别子级',
key: 'majorTypeChild',
width: 130,
type: JVxeTypes.input,
},
{
title: '主考科目',
key: 'mainSubjects',
width: 130,
type: JVxeTypes.input,
},
{
title: '年份',
key: 'year',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '科类(文科/理科)',
key: 'category',
width: 100,
type: JVxeTypes.input,
},
{
title: '批次',
key: 'batch',
width: 100,
type: JVxeTypes.input,
},
{
title: '录取方式(文*x+专*y)',
key: 'rulesEnrollProbability',
width: 150,
type: JVxeTypes.input,
},
{
title: '录取概率计算规则运算符',
key: 'probabilityOperator',
width: 150,
type: JVxeTypes.input,
},
{
title: '省控线',
key: 'controlLine',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '录取线',
key: 'admissionLine',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '招生人数',
key: 'enrollNum',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '实际投档人数',
key: 'actualPitcherNum',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '录取数',
key: 'admissionNum',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '一志愿录取数',
key: 'oneVolunteerAdmissionNum',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '最低分数差',
key: 'scoreLineDifference',
width: 100,
type: JVxeTypes.inputNumber,
},
{
title: '学费',
key: 'tuition',
width: 200,
type: JVxeTypes.input,
},
{
title: '备注',
key: 'detail',
width: 200,
type: JVxeTypes.textarea,
}
]);
const [messageApi, contextHolder] = message.useMessage(); const [messageApi, contextHolder] = message.useMessage();
const { prefixCls,tableContext,onImportXls } = useListPage({ const { prefixCls,tableContext,onImportXls } = useListPage({
tableProps:{ tableProps:{
@ -291,18 +153,6 @@ const { prefixCls,tableContext,onImportXls } = useListPage({
}) })
// url // url
enum Api {
getData = '/yx/yxHistoryMajorEnroll/list',
//
saveRow = '/yx/yxHistoryMajorEnroll/edit',
//
saveAll = '/yx/yxHistoryMajorEnroll/saveBatch',
deleteBatch = '/yx/yxHistoryMajorEnroll/deleteBatch',
importExcel = '/yx/yxHistoryMajorEnroll/importExcel',
exportXls = '/yx/yxHistoryMajorEnroll/exportXls',
renewControlLine = '/yx/yxHistoryMajorEnroll/renewControlLine'
}
loadData(); loadData();
async function searchQuery() { async function searchQuery() {
@ -318,6 +168,7 @@ async function searchReset() {
queryParam.majorType = ''// queryParam.majorType = ''//
queryParam.category = ''// queryParam.category = ''//
queryParam.year = '' queryParam.year = ''
queryParam.batch = ''
loadData() loadData()
} }
@ -328,7 +179,7 @@ async function loadData() {
await defHttp await defHttp
.get({ .get({
// //
url: Api.getData, url: getData,
// //
params: { params: {
schoolCode: queryParam.schoolCode ? '*' + queryParam.schoolCode + '*' : '', schoolCode: queryParam.schoolCode ? '*' + queryParam.schoolCode + '*' : '',
@ -336,6 +187,7 @@ async function loadData() {
majorType: queryParam.majorType, majorType: queryParam.majorType,
category: queryParam.category, category: queryParam.category,
year: queryParam.year, year: queryParam.year,
batch: queryParam.batch,
pageNo: pagination.current, pageNo: pagination.current,
pageSize: pagination.pageSize, pageSize: pagination.pageSize,
}, },
@ -355,7 +207,7 @@ async function loadData() {
} }
//线 //线
async function renewControlLine(){ async function handleRenewControlLine(){
console.log('刷新省控线') console.log('刷新省控线')
let selections = '' let selections = ''
if (selectedRows.value) { if (selectedRows.value) {
@ -376,7 +228,7 @@ async function renewControlLine(){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
defHttp defHttp
.post({ .post({
url: Api.renewControlLine, url: renewControlLine,
params: {id:selections}, params: {id:selections},
}) })
.then((res) => { .then((res) => {
@ -419,7 +271,7 @@ function handleTableSave({$table, target}) {
loading.value = true; loading.value = true;
defHttp defHttp
.post({ .post({
url: Api.saveAll, url: saveAll,
params: tableData, params: tableData,
}) })
.then(() => { .then(() => {
@ -444,7 +296,7 @@ function handleTableRemove(event) {
window.setTimeout(() => { window.setTimeout(() => {
defHttp defHttp
.delete({ .delete({
url: Api.deleteBatch, data: {ids: deleteIds.join(',')} url: deleteBatch, data: {ids: deleteIds.join(',')}
}, {joinParamsToUrl: true}) }, {joinParamsToUrl: true})
.then((res) => { .then((res) => {
createMessage.success('删除成功'); createMessage.success('删除成功');
@ -472,7 +324,7 @@ function handleEditClosed(event) {
console.log('即时保存数据:', row); console.log('即时保存数据:', row);
defHttp defHttp
.put({ .put({
url: Api.saveRow, url: saveRow,
params: row, params: row,
}) })
.then((res) => { .then((res) => {
@ -514,7 +366,7 @@ function handleSelectRowChange(event) {
* @param name * @param name
* @param url * @param url
*/ */
async function exportXls(isXlsx = false) { async function onExportXls(isXlsx = false) {
let name = '' let name = ''
let selections = '' let selections = ''
if (selectedRows.value) { if (selectedRows.value) {
@ -523,7 +375,7 @@ async function exportXls(isXlsx = false) {
}) })
console.log(selectedRows.value) console.log(selectedRows.value)
} }
const data = await defHttp.get({ url: Api.exportXls, params: {selections:selections}, responseType: 'blob', timeout: 60000 }, { isTransformResponse: false }); const data = await defHttp.get({ url: getExportUrl, params: {selections:selections}, responseType: 'blob', timeout: 60000 }, { isTransformResponse: false });
if (!data) { if (!data) {
createMessage.warning('文件下载失败'); createMessage.warning('文件下载失败');
return; return;

View File

@ -11,6 +11,7 @@ enum Api {
deleteBatch = '/yx/yxOrder/deleteBatch', deleteBatch = '/yx/yxOrder/deleteBatch',
importExcel = '/yx/yxOrder/importExcel', importExcel = '/yx/yxOrder/importExcel',
exportXls = '/yx/yxOrder/exportXls', exportXls = '/yx/yxOrder/exportXls',
refundUrl = '/yx/yxOrder/refund',
} }
/** /**
* api * api
@ -62,3 +63,8 @@ export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save; let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params}); return defHttp.post({url: url, params});
} }
export const refund = (params)=>{
return defHttp.post({url: Api.refundUrl, params});
}

View File

@ -21,22 +21,41 @@ export const columns: BasicColumn[] = [
return '未知'; return '未知';
}, },
}, },
{
title: '退款金额',
align: "center",
dataIndex: 'refundAmount',
customRender: ({text}) => {
if(text){
return parseFloat(text)/100
}
return '';
},
},
{ {
title: '商品编号', title: '商品编号',
align: "center", align: "center",
dataIndex: 'skuCode', dataIndex: 'skuCode',
customRender: ({text}) => { customRender: ({text}) => {
if (text === '1001') { if (text === '1001') {
return '体验卡'; return '艺体志愿宝-体验卡';
}else if(text ==='1002'){ }else if(text ==='1002'){
return 'VIP'; return '艺体志愿宝-VIP';
}else if(text ==='9999'){ }else if(text ==='9999'){
return '管理员'; return '艺体志愿宝-管理员';
}else if(text ==='2002'){
return '体育志愿宝-VIP';
}else{ }else{
return '未知'; return '未知';
} }
}, },
}, },
{
title: '操作平台',
//1借记卡、2信用卡、3微信、4支付宝、5现金
align: "center",
dataIndex: 'provider',
},
{ {
title: '支付方式', title: '支付方式',
//1借记卡、2信用卡、3微信、4支付宝、5现金 //1借记卡、2信用卡、3微信、4支付宝、5现金
@ -68,6 +87,14 @@ export const columns: BasicColumn[] = [
sorter: { sorter: {
multiple: 2 multiple: 2
} }
},{
title: '退款时间',
align: "center",
dataIndex: 'refundTime',//paymentUserId
resizable: true,
sorter: {
multiple: 2
}
}, },
]; ];
//查询数据 //查询数据

View File

@ -11,14 +11,36 @@
allowClear="true"></a-input> allowClear="true"></a-input>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="3"> <a-col :span="4">
<a-form-item label="商品类型" name="skuCode"> <a-form-item label="商品类型" name="skuCode">
<a-select v-model:value="queryParam.skuCode" show-search allow-clear <a-select v-model:value="queryParam.skuCode" show-search allow-clear
placeholder="请选择"> placeholder="请选择">
<a-select-option value="">请选择</a-select-option> <a-select-option value="">请选择</a-select-option>
<a-select-option value="1001">体验卡</a-select-option> <a-select-option value="1001">艺体志愿宝-体验卡</a-select-option>
<a-select-option value="1002">VIP</a-select-option> <a-select-option value="1002">艺体志愿宝-VIP</a-select-option>
<a-select-option value="9999">管理员</a-select-option> <a-select-option value="9999">艺体志愿宝-管理员</a-select-option>
<a-select-option value="2002">体育志愿宝-VIP</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item label="操作平台" name="provider">
<a-select v-model:value="queryParam.provider" show-search allow-clear
placeholder="请选择">
<a-select-option value="">请选择</a-select-option>
<a-select-option value="wxpay">微信</a-select-option>
<a-select-option value="toutiao">抖音</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item label="支付方式" name="paymentType">
<a-select v-model:value="queryParam.paymentType" show-search allow-clear
placeholder="请选择">
<a-select-option value="">请选择</a-select-option>
<a-select-option value="3">微信</a-select-option>
<a-select-option value="4">抖音</a-select-option>
<a-select-option value="10">支付宝</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-col> </a-col>
@ -29,10 +51,13 @@
<a-select-option value="">请选择</a-select-option> <a-select-option value="">请选择</a-select-option>
<a-select-option value="1">{{getStatusText("1")}}</a-select-option> <a-select-option value="1">{{getStatusText("1")}}</a-select-option>
<a-select-option value="2">{{getStatusText("2")}}</a-select-option> <a-select-option value="2">{{getStatusText("2")}}</a-select-option>
<a-select-option value="8">{{getStatusText("8")}}</a-select-option>
<a-select-option value="-1">{{getStatusText("-1")}}</a-select-option> <a-select-option value="-1">{{getStatusText("-1")}}</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row>
<a-row>
<a-col :span="12"> <a-col :span="12">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button> <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button> <a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
@ -61,29 +86,42 @@
</a-button> </a-button>
</a-dropdown> </a-dropdown>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<Tag v-if="column.key === 'provider' &&record.provider==='wxpay'" color="success">
微信
</Tag>
<Tag v-if="column.key === 'provider' && record.provider==='toutiao'" color="default">
抖音
</Tag>
<a-tag v-if="column.key === 'paymentType' && record.paymentType==='3'" color="success"> <a-tag v-if="column.key === 'paymentType' && record.paymentType==='3'" color="success">
<template #icon> <template #icon>
<wechat-outlined/> <wechat-outlined/>
</template> </template>
微信支付 微信支付
</a-tag> </a-tag>
<!-- <AlipayCircleOutlined />--> <a-tag v-if="column.key === 'paymentType' && record.paymentType==='4'" color="success">
<template #icon>
<alipay-circle-outlined/>
</template>
支付宝支付
</a-tag>
<a-tag v-if="column.key === 'paymentType' && record.paymentType==='10'" color="success">
抖音支付
</a-tag>
<Tag v-if="column.key === 'orderStatus'" :color="getStatusColor(record.orderStatus)"> <Tag v-if="column.key === 'orderStatus'" :color="getStatusColor(record.orderStatus)">
{{ getStatusText(record.orderStatus) }} {{ getStatusText(record.orderStatus) }}
</Tag> </Tag>
</template> </template>
<!-- <template #category="{ record }">
<Tag color="green">
{{ record.orderStatus }}
</Tag>
</template>-->
<!--操作栏--> <!--操作栏-->
<template #action="{ record }"> <template #action="{ record }">
<TableAction :actions="getTableAction(record)" <TableAction :actions="getTableAction(record)" />
:dropDownActions="getDropDownAction(record)"/> <!-- :dropDownActions="getDropDownAction(record)"-->
</template> </template>
<!--字段回显插槽--> <!--字段回显插槽-->
<template #htmlSlot="{text}"> <template #htmlSlot="{text}">
@ -102,13 +140,21 @@
</BasicTable> </BasicTable>
<!-- 表单区域 --> <!-- 表单区域 -->
<YxOrderModal @register="registerModal" @success="handleSuccess"></YxOrderModal> <YxOrderModal @register="registerModal" @success="handleSuccess"></YxOrderModal>
<a-modal v-model:open="refundInfo.refundModalVisible" title="订单退款" @ok="handleRefundOk()">
<div style="padding:10px 30px">
<p>金额将原路退回退款后用户的会员身份将移除</p>
<a-input-number v-model:value="refundInfo.refundAmount" addon-before="退款金额" addon-after=""></a-input-number>
<a-textarea style="margin: 5px 0" placeholder="退款原因" v-model:value="refundInfo.refundReason" show-count :maxlength="200" />
</div>
</a-modal>
</div> </div>
</template> </template>
<script lang="ts" name="yx-yxOrder" setup> <script lang="ts" name="yx-yxOrder" setup>
import {ref, computed, unref, reactive} from 'vue'; import {ref, computed, unref, reactive} from 'vue';
import { import {
WechatOutlined, WechatOutlined,AlipayCircleOutlined,
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import {Tag, Avatar} from 'ant-design-vue'; import {Tag, Avatar} from 'ant-design-vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table'; import {BasicTable, useTable, TableAction} from '/@/components/Table';
@ -116,13 +162,19 @@ import {useModal} from '/@/components/Modal';
import {useListPage} from '/@/hooks/system/useListPage' import {useListPage} from '/@/hooks/system/useListPage'
import YxOrderModal from './components/YxOrderModal.vue' import YxOrderModal from './components/YxOrderModal.vue'
import {columns, searchFormSchema} from './YxOrder.data'; import {columns, searchFormSchema} from './YxOrder.data';
import {list, deleteOne, batchDelete, getImportUrl, getExportUrl} from './YxOrder.api'; import {list, deleteOne, batchDelete,refund, getImportUrl, getExportUrl} from './YxOrder.api';
import {downloadFile} from '/@/utils/common/renderUtils'; import {downloadFile} from '/@/utils/common/renderUtils';
const checkedKeys = ref<Array<string | number>>([]); const checkedKeys = ref<Array<string | number>>([]);
const queryParam = reactive<any>({}); const queryParam = reactive<any>({});
//model //model
const [registerModal, {openModal}] = useModal(); const [registerModal, {openModal}] = useModal();
const refundInfo = reactive({
id:'' as any,
refundReason:'' as String,
refundAmount:0 as Number,
refundModalVisible:false as boolean,
})
const labelCol = reactive({ const labelCol = reactive({
xs: {span: 24}, xs: {span: 24},
sm: {span: 7}, sm: {span: 7},
@ -151,11 +203,11 @@ const {prefixCls, tableContext, onExportXls, onImportXls} = useListPage({
}, },
bordered: true, bordered: true,
showTableSetting: false, showTableSetting: false,
showActionColumn: false,// showActionColumn: true,//
/*actionColumn: { actionColumn: {
width: 120, width: 120,
fixed: 'right' fixed: 'right'
},*/ },
}, },
exportConfig: { exportConfig: {
name: "订单表", name: "订单表",
@ -190,6 +242,22 @@ function handleEdit(record: Recordable) {
}); });
} }
function handleRefund(record:Recordable){
console.log(record)
refundInfo.id = record.id
refundInfo.refundReason = '不想要了。'
if(record.totalAmount){
refundInfo.refundAmount = record.totalAmount/100;
}
refundInfo.refundModalVisible = true
}
// 退
async function handleRefundOk(){
await refund(refundInfo)
refundInfo.refundModalVisible = false
}
/** /**
* 详情 * 详情
*/ */
@ -226,12 +294,20 @@ function handleSuccess() {
* 操作栏 * 操作栏
*/ */
function getTableAction(record) { function getTableAction(record) {
return [ if(record.provider==='toutiao' && record.orderStatus==='2'){
{ return [
label: '编辑', {
onClick: handleEdit.bind(null, record), label: '退款',
} onClick: handleRefund.bind(null, record),
] }
/*{
label: '编辑',
onClick: handleEdit.bind(null, record),
}*/
]
}
return []
} }
/** /**
@ -267,6 +343,8 @@ function getStatusText(orderStatus) {
return '未付款'; return '未付款';
} else if (orderStatus === '2') { } else if (orderStatus === '2') {
return '已付款'; return '已付款';
} else if (orderStatus === '8') {
return '已退款';
} else { } else {
return '未知'; return '未知';
} }
@ -289,6 +367,8 @@ function searchReset() {
queryParam.orderCode='' queryParam.orderCode=''
queryParam.skuCode='' queryParam.skuCode=''
queryParam.orderStatus='' queryParam.orderStatus=''
queryParam.provider = ''
queryParam.paymentType = ''
selectedRowKeys.value = []; selectedRowKeys.value = [];
// //
reload(); reload();

View File

@ -1,44 +1,61 @@
import {defHttp} from '/@/utils/http/axios'; import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage"; import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage(); const { createConfirm } = useMessage();
enum Api { enum Api {
getData = '/yx/yxSchool/list',
// 模拟保存单行数据(即时保存)
saveRow = '/yx/yxSchool/edit',
// 模拟保存整个表格的数据
saveAll = '/yx/yxSchool/saveBatch',
list = '/yx/yxSchool/list', list = '/yx/yxSchool/list',
save='/yx/yxSchool/add', save = '/yx/yxSchool/add',
edit='/yx/yxSchool/edit', edit = '/yx/yxSchool/edit',
deleteOne = '/yx/yxSchool/delete', deleteOne = '/yx/yxSchool/delete',
deleteBatch = '/yx/yxSchool/deleteBatch', deleteBatch = '/yx/yxSchool/deleteBatch',
importExcel = '/yx/yxSchool/importExcel', importExcel = '/yx/yxSchool/importExcel',
exportXls = '/yx/yxSchool/exportXls', exportXls = '/yx/yxSchool/exportXls',
queryNotHasSchool = '/yx/yxSchool/queryNotHasSchool',
} }
export const queryNotHasSchool = Api.queryNotHasSchool;
export const getData = Api.getData;
export const saveRow = Api.saveRow;
export const saveAll = Api.saveAll;
export const deleteBatch = Api.deleteBatch;
/** /**
* api * api
* @param params * @param params
*/ */
export const getExportUrl = Api.exportXls; export const getExportUrl = Api.exportXls;
/** /**
* api * api
*/ */
export const getImportUrl = Api.importExcel; export const getImportUrl = Api.importExcel;
/** /**
* *
* @param params * @param params
*/ */
export const list = (params) => export const list = (params) => defHttp.get({ url: Api.list, params });
defHttp.get({url: Api.list, params});
/** /**
* *
* @param params
* @param handleSuccess
*/ */
export const deleteOne = (params,handleSuccess) => { export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess(); handleSuccess();
}); });
} }
/** /**
* *
* @param params * @param params
* @param handleSuccess
*/ */
export const batchDelete = (params, handleSuccess) => { export const batchDelete = (params, handleSuccess) => {
createConfirm({ createConfirm({
@ -54,11 +71,13 @@ export const batchDelete = (params, handleSuccess) => {
} }
}); });
} }
/** /**
* *
* @param params * @param params
* @param isUpdate
*/ */
export const saveOrUpdate = (params, isUpdate) => { export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save; let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params}); return defHttp.post({ url: url, params }, { isTransformResponse: false });
} }

View File

@ -2,146 +2,489 @@ import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table'; import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator'; import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils'; import { render } from '/@/utils/common/renderUtils';
import { ref} from 'vue';
import { JVxeColumn, JVxeTypes } from "@/components/jeecg/JVxeTable/src/types";
//列表数据 //列表数据
export const columns: BasicColumn[] = [
{ export const columns = ref<JVxeColumn[]>([
/*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/
{
title: '操作',
key: 'action',
type: JVxeTypes.slot,
fixed: 'right',
minWidth: 60,
align: 'center',
slotName: 'myAction',
showSub: false,
},
{
title: '操作',
key: 'action2',
type: JVxeTypes.slot,
fixed: 'right',
minWidth: 60,
align: 'center',
slotName: 'myAction2',
showSub: true,
},
{
title: '学校名称', title: '学校名称',
align:"center", align: "center",
dataIndex: 'schoolName' key: 'schoolName',
}, // 列的宽度
{ width: 200,
title: '学校编码', // 如果加上了该属性就代表当前单元格是可编辑的type就是表单的类型input就是简单的输入框
align:"center", type: JVxeTypes.input,
dataIndex: 'schoolCode' showSub: false,
}, },
{ {
title: '院校编码', title: '旧院校名称',
align:"center", align: "center",
dataIndex: 'institutionCode' key: 'oldSchoolName',
}, width: 200,
{ type: JVxeTypes.input,
showSub: false,
},
{
title: '官方网址', title: '官方网址',
align:"center", align: "center",
dataIndex: 'schoolWebsiteAddress' key: 'schoolWebsiteAddress',
}, width: 200,
{ type: JVxeTypes.input,
showSub: false,
},
{
title: '学校电话', title: '学校电话',
align:"center", align: "center",
dataIndex: 'schoolPhone' key: 'schoolPhone',
}, width: 200,
{ type: JVxeTypes.input,
showSub: false,
},
{
title: '电子邮箱', title: '电子邮箱',
align:"center", align: "center",
dataIndex: 'schoolEmail' key: 'schoolEmail',
}, width: 200,
{ type: JVxeTypes.input,
showSub: false,
},
{
title: '学校图标', title: '学校图标',
align:"center", align: "center",
dataIndex: 'schoolIcon', key: 'schoolIcon',
customRender:render.renderImage, // customRender: render.renderImage,
}, showSub: false,
{ type: JVxeTypes.image,
width: 180,
maxCount: 1,
},
{
title: '办学日期', title: '办学日期',
align:"center", align: "center",
dataIndex: 'schoolOpenDate', key: 'schoolOpenDate',
customRender:({text}) =>{ width:100,
return !text?"":(text.length>10?text.substr(0,10):text) type: JVxeTypes.input,
}, showSub: false,
}, },
{ {
title: '省', title: '省份',
align:"center", align: "center",
dataIndex: 'province' key: 'province',
}, width:100,
{ type: JVxeTypes.input,
title: '市', showSub: false,
align:"center", },
dataIndex: 'city' {
}, title: '城市',
{ align: "center",
title: '区', key: 'city',
align:"center", width:100,
dataIndex: 'area' type: JVxeTypes.input,
}, showSub: false,
{ },
{
title: '区域',
align: "center",
key: 'area',
width:100,
type: JVxeTypes.input,
showSub: false,
},
{
title: '详细地址', title: '详细地址',
align:"center", align: "center",
dataIndex: 'street' key: 'street',
}, width: 300,
{ type: JVxeTypes.textarea,
showSub: false,
},
{
title: '隶属于', title: '隶属于',
align:"center", align: "center",
dataIndex: 'affiliation' key: 'affiliation',
}, width:100,
{ type: JVxeTypes.input,
showSub: false,
},
{
title: '办学性质', title: '办学性质',
align:"center", align: "center",
dataIndex: 'schoolNature' key: 'schoolNature',
}, type: JVxeTypes.select,
{ showSub: false,
width: 180,
// 下拉选项
options: [
{ title: '公办', value: '公办' },
{ title: '民办', value: '民办' },
{ title: '中外合作办学', value: '中外合作办学' },
{ title: '内地与港澳台地区合作办学', value: '内地与港澳台地区合作办学' },
],
allowSearch: true,
placeholder: '请选择',
},
{
title: '院校类型', title: '院校类型',
align:"center", align: "center",
dataIndex: 'institutionType' key: 'institutionType',
}, width:100,
{ type: JVxeTypes.input,
title: '博士点', showSub: false,
align:"center", },
dataIndex: 'doctoralPoint' {
}, title: '办学类型',
{ align: "center",
title: '硕士点', key: 'schoolType',
align:"center", width:100,
dataIndex: 'masterPoint' type: JVxeTypes.input,
}, showSub: false,
{ },
title: '重点学科', {
align:"center",
dataIndex: 'keyDisciplines'
},
{
title: '重点实验室',
align:"center",
dataIndex: 'keyLaboratory'
},
{
title: '学生人数', title: '学生人数',
align:"center", align: "center",
dataIndex: 'studentNum' key: 'studentNum',
}, width:100,
{ type: JVxeTypes.input,
title: '标签', showSub: false,
align:"center", },
dataIndex: 'tags' // {
}, // title: '学校批次',
{ // align: "center",
title: '学校批次', // key: 'schoolBatch',
align:"center", // width:100,
dataIndex: 'schoolBatch' // type: JVxeTypes.input,
}, // showSub: false,
{ // },
{
title: '985工程', title: '985工程',
align:"center", align: "center",
dataIndex: 'is985' key: 'is985',
}, type: JVxeTypes.checkbox,
{ width: 100,
customValue: ['1', '0'], // true ,false
defaultChecked: false,
showSub: false,
},
{
title: '211工程', title: '211工程',
align:"center", align: "center",
dataIndex: 'is211' key: 'is211',
}, type: JVxeTypes.checkbox,
{ width: 100,
customValue: ['1', '0'], // true ,false
defaultChecked: false,
showSub: false,
},
{
title: '强基计划', title: '强基计划',
align:"center", align: "center",
dataIndex: 'isStrengthen' key: 'isStrengthen',
}, type: JVxeTypes.checkbox,
{ width: 100,
customValue: ['1', '0'], // true ,false
defaultChecked: false,
showSub: false,
},
{
title: '一流大学',
align: "center",
key: 'yldx',
width:150,
type: JVxeTypes.input,
showSub: false,
},
{
title: '国重/省重',
align: "center",
key: 'gzsz',
width:150,
type: JVxeTypes.input,
showSub: false,
},
{
title: '保研率',
align: "center",
key: 'byl',
width:120,
type: JVxeTypes.input,
showSub: false,
},
{
title: '国家特色专业',
align: "center",
key: 'gjtszy',
width:150,
type: JVxeTypes.input,
showSub: false,
},
{
title: '省特色专业',
align: "center",
key: 'stszy',
width:150,
type: JVxeTypes.input,
showSub: false,
},
{
title: '是否国重点',
align: "center",
key: 'gzd',
type: JVxeTypes.checkbox,
width: 100,
customValue: ['1', '0'], // true ,false
defaultChecked: false,
showSub: false,
},
{
title: '世界一流',
align: "center",
key: 'sjyl',
width:120,
type: JVxeTypes.input,
showSub: false,
},
{
title: '是否双一流',
align: "center",
key: 'sfsyl',
type: JVxeTypes.checkbox,
width: 100,
customValue: ['1', '0'], // true ,false
defaultChecked: false,
showSub: false,
},
{
title: '占地面积(亩)', title: '占地面积(亩)',
align:"center", align: "center",
key: 'are',
width:120,
type: JVxeTypes.input,
showSub: false,
},
{
title: '男生占比',
align: "center",
key: 'maleRatio',
width:120,
type: JVxeTypes.input,
showSub: false,
},
{
title: '女生占比',
align: "center",
key: 'femaleRatio',
width:120,
type: JVxeTypes.input,
showSub: false,
},
{
title: '艺术院校',
align: "center",
key: 'isYs',
type: JVxeTypes.checkbox,
width: 100,
customValue: ['1', '0'], // true ,false
defaultChecked: false,
showSub: false,
},
]);
export const columns2: BasicColumn[] = [
{
title: '学校名称',
align: "center",
dataIndex: 'schoolName'
},
{
title: '旧院校名称',
align: "center",
dataIndex: 'oldSchoolName'
},
{
title: '官方网址',
align: "center",
dataIndex: 'schoolWebsiteAddress'
},
{
title: '学校电话',
align: "center",
dataIndex: 'schoolPhone'
},
{
title: '电子邮箱',
align: "center",
dataIndex: 'schoolEmail'
},
{
title: '学校图标',
align: "center",
dataIndex: 'schoolIcon',
customRender: render.renderImage,
},
{
title: '办学日期',
align: "center",
dataIndex: 'schoolOpenDate'
},
{
title: '省份',
align: "center",
dataIndex: 'province'
},
{
title: '城市',
align: "center",
dataIndex: 'city'
},
{
title: '区域',
align: "center",
dataIndex: 'area'
},
{
title: '详细地址',
align: "center",
dataIndex: 'street'
},
{
title: '隶属于',
align: "center",
dataIndex: 'affiliation'
},
{
title: '办学性质',
align: "center",
dataIndex: 'schoolNature'
},
{
title: '院校类型',
align: "center",
dataIndex: 'institutionType'
},
{
title: '办学类型',
align: "center",
dataIndex: 'schoolType'
},
{
title: '学生人数',
align: "center",
dataIndex: 'studentNum'
},
{
title: '标签',
align: "center",
dataIndex: 'tags'
},
{
title: '学校批次',
align: "center",
dataIndex: 'schoolBatch'
},
{
title: '985工程',
align: "center",
dataIndex: 'is985'
},
{
title: '211工程',
align: "center",
dataIndex: 'is211'
},
{
title: '强基计划',
align: "center",
dataIndex: 'isStrengthen'
},
{
title: '一流大学',
align: "center",
dataIndex: 'yldx'
},
{
title: '国重/省重',
align: "center",
dataIndex: 'gzsz'
},
{
title: '保研率',
align: "center",
dataIndex: 'byl'
},
{
title: '国家特色专业',
align: "center",
dataIndex: 'gjtszy'
},
{
title: '省特色专业',
align: "center",
dataIndex: 'stszy'
},
{
title: '是否国重点',
align: "center",
dataIndex: 'gzd'
},
{
title: '世界一流',
align: "center",
dataIndex: 'sjyl'
},
{
title: '是否双一流',
align: "center",
dataIndex: 'sfsyl'
},
{
title: '占地面积(亩)',
align: "center",
dataIndex: 'are' dataIndex: 'are'
}, },
{
title: '男生占比',
align: "center",
dataIndex: 'maleRatio'
},
{
title: '女生占比',
align: "center",
dataIndex: 'femaleRatio'
},
{
title: '是否是艺术',
align: "center",
dataIndex: 'isYs'
},
]; ];
//查询数据 //查询数据
export const searchFormSchema: FormSchema[] = [ export const searchFormSchema: FormSchema[] = [
]; ];
//表单数据 //表单数据
export const formSchema: FormSchema[] = [ export const formSchema: FormSchema[] = [
{ {
@ -150,13 +493,8 @@ export const formSchema: FormSchema[] = [
component: 'Input', component: 'Input',
}, },
{ {
label: '学校编码', label: '旧院校名称',
field: 'schoolCode', field: 'oldSchoolName',
component: 'Input',
},
{
label: '院校编码',
field: 'institutionCode',
component: 'Input', component: 'Input',
}, },
{ {
@ -177,27 +515,27 @@ export const formSchema: FormSchema[] = [
{ {
label: '学校图标', label: '学校图标',
field: 'schoolIcon', field: 'schoolIcon',
component: 'JImageUpload', component: 'JImageUpload',
componentProps:{ componentProps:{
}, },
}, },
{ {
label: '办学日期', label: '办学日期',
field: 'schoolOpenDate', field: 'schoolOpenDate',
component: 'DatePicker', component: 'Input',
}, },
{ {
label: '省', label: '省',
field: 'province', field: 'province',
component: 'Input', component: 'Input',
}, },
{ {
label: '市', label: '市',
field: 'city', field: 'city',
component: 'Input', component: 'Input',
}, },
{ {
label: '区', label: '区',
field: 'area', field: 'area',
component: 'Input', component: 'Input',
}, },
@ -222,24 +560,9 @@ export const formSchema: FormSchema[] = [
component: 'Input', component: 'Input',
}, },
{ {
label: '博士点', label: '办学类型',
field: 'doctoralPoint', field: 'schoolType',
component: 'InputNumber', component: 'Input',
},
{
label: '硕士点',
field: 'masterPoint',
component: 'InputNumber',
},
{
label: '重点学科',
field: 'keyDisciplines',
component: 'InputNumber',
},
{
label: '重点实验室',
field: 'keyLaboratory',
component: 'InputNumber',
}, },
{ {
label: '学生人数', label: '学生人数',
@ -251,11 +574,6 @@ export const formSchema: FormSchema[] = [
field: 'baseInfo', field: 'baseInfo',
component: 'JEditor', component: 'JEditor',
}, },
{
label: '历史文化',
field: 'hisotryCulture',
component: 'JEditor',
},
{ {
label: '标签', label: '标签',
field: 'tags', field: 'tags',
@ -281,27 +599,71 @@ export const formSchema: FormSchema[] = [
field: 'isStrengthen', field: 'isStrengthen',
component: 'InputNumber', component: 'InputNumber',
}, },
{
label: '一流大学',
field: 'yldx',
component: 'Input',
},
{
label: '国重/省重',
field: 'gzsz',
component: 'Input',
},
{
label: '保研率',
field: 'byl',
component: 'Input',
},
{
label: '国家特色专业',
field: 'gjtszy',
component: 'Input',
},
{
label: '省特色专业',
field: 'stszy',
component: 'Input',
},
{
label: '是否国重点',
field: 'gzd',
component: 'Input',
},
{
label: '世界一流',
field: 'sjyl',
component: 'Input',
},
{
label: '是否双一流',
field: 'sfsyl',
component: 'Input',
},
{ {
label: '占地面积(亩)', label: '占地面积(亩)',
field: 'are', field: 'are',
component: 'InputNumber', component: 'InputNumber',
},
{
label: '男生占比',
field: 'maleRatio',
component: 'InputNumber',
},
{
label: '女生占比',
field: 'femaleRatio',
component: 'InputNumber',
},
{
label: '是否是艺术',
field: 'isYs',
component: 'InputNumber',
}, },
// TODO 主键隐藏字段目前写死为ID // TODO 主键隐藏字段目前写死为ID
{ {
label: '', label: '',
field: 'id', field: 'id',
component: 'Input', component: 'Input',
show: false show: false,
}, },
]; ];
/**
* formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[]{
// 默认和原始表单保持一致 如果流程中配置了权限数据这里需要单独处理formSchema
return formSchema;
}

View File

@ -1,173 +1,574 @@
<template> <template>
<div> <a-card title="" :bordered="false">
<!--引用表格--> <a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam"
<BasicTable @register="registerTable" :rowSelection="rowSelection"> :label-col="labelCol" :wrapper-col="wrapperCol">
<!--插槽:table标题--> <a-row>
<template #tableTitle> <a-col :span="4">
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> <a-form-item label="学校代码">
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> <a-input v-model:value="queryParam.schoolCode" placeholder="请输入学校代码" allowClear/>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> </a-form-item>
<a-dropdown v-if="selectedRowKeys.length > 0"> </a-col>
<template #overlay> <a-col :span="4">
<a-menu> <a-form-item label="学校名称">
<a-menu-item key="1" @click="batchHandleDelete"> <a-input v-model:value="queryParam.schoolName" placeholder="请输入学校名称" allowClear/>
<Icon icon="ant-design:delete-outlined"></Icon> </a-form-item>
删除 </a-col>
</a-menu-item> </a-row>
</a-menu> <a-row>
</template> <a-col :span="12">
<a-button>批量操作 <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<Icon icon="mdi:chevron-down"></Icon> <a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
</a-button> <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchNotHasSchool" style="margin-left: 8px">查询缺失院校</a-button>
</a-dropdown> <a-button type="primary" preIcon="ant-design:export-outlined" @click="exportXls" style="margin: 8px">导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls" style="margin-left: 8px">导入</j-upload-button>
</a-col>
</a-row>
</a-form>
<!--
即时保存大体思路
1. JVxeTable 上必须加 keep-source 属性
2. 监听 edit-closed事件这个事件是在编辑完成后触发
3. 在这个事件里面判断数据是否更改如果更改了就调用接口进行保存操作
-->
<JVxeTable
toolbar
:toolbarConfig="toolbarConfig"
rowSelection
keepSource
asyncRemove
clickRowShowSubForm
:height="500"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:pagination="pagination"
@save="handleTableSave"
@removed="handleTableRemove"
@edit-closed="handleEditClosed"
@pageChange="handlePageChange"
@valueChange="handleValueChange"
@selectRowChange="handleSelectRowChange"
>
<template #myAction="props">
<a @click="handleEdit(props)">编辑</a>
</template> </template>
<!--操作栏-->
<template #action="{ record }"> <template #myAction2="props">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> <a @click="handleShowSub(props)">子级</a>
</template> </template>
<!--字段回显插槽-->
<template #htmlSlot="{text}"> <!-- 子表单 -->
<div v-html="text"></div> <template #subForm="{row}">
<template v-if="subTable.flag">
<JVxeTable
toolbar
:toolbarConfig="subToolbarConfig"
rowSelection
ref="subFormTable"
height="auto"
:max-height="350"
:loading="subTable.loading"
:columns="subTable.columns"
:dataSource="subTable.dataSource"
@removed="handleSubTableRemove"
@edit-closed="handleSubEditClosed"
></JVxeTable>
</template>
</template> </template>
<!--省市区字段回显插槽--> </JVxeTable>
<template #pcaSlot="{text}"> </a-card>
{{ getAreaTextByCode(text) }} <NotSchoolModal @register="registerNotSchool" />
</template>
<template #fileSlot="{text}"> <a-modal v-model:open="open" title="缺失院校" @ok="handleOk">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> <div class="pt-3px pr-3px">
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> <a-table :columns="state.columns" :data-source="state.notSchoolList" :hideOnSinglePage="true" />
</template> </div>
</BasicTable> </a-modal>
<!-- 表单区域 -->
<YxSchoolModal @register="registerModal" @success="handleSuccess"></YxSchoolModal> <!-- 表单区域 -->
</div> <YxSchoolModal ref="registerModal" @success="handleSuccess"></YxSchoolModal>
</template> </template>
<script lang="ts" name="yx-yxSchool" setup> <script lang="ts" setup>
import {ref, computed, unref} from 'vue'; //
import {BasicTable, useTable, TableAction} from '/@/components/Table'; import {reactive, ref} from 'vue';
import {useModal} from '/@/components/Modal'; import {defHttp} from '/@/utils/http/axios';
import { useListPage } from '/@/hooks/system/useListPage' import {JVxeTypes} from '/@/components/jeecg/JVxeTable/types';
import YxSchoolModal from './components/YxSchoolModal.vue' import {useMessage} from '/@/hooks/web/useMessage';
import {columns, searchFormSchema} from './YxSchool.data'; import { useListPage } from '/@/hooks/system/useListPage';
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './YxSchool.api'; import {getData,saveRow,saveAll,deleteBatch, getExportUrl, getImportUrl, queryNotHasSchool } from "@/views/yx/yxSchool/YxSchool.api";
import { downloadFile } from '/@/utils/common/renderUtils'; import {columns as tableColumns } from "@/views/yx/yxSchool/YxSchool.data";
const checkedKeys = ref<Array<string | number>>([]); import YxSchoolModal from "@/views/yx/yxSchool/components/YxSchoolModal.vue";
//model import { useModal } from "@/components/Modal";
const [registerModal, {openModal}] = useModal(); import NotSchoolModal from "@/views/yx/yxSchool/components/NotSchoolModal.vue";
//table
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '学校信息表',
api: list,
columns,
canResize:false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter:true,
showAdvancedButton:true,
fieldMapToNumber: [
],
fieldMapToTime: [
],
},
actionColumn: {
width: 120,
fixed:'right'
},
},
exportConfig: {
name:"学校信息表",
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
})
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext const registerModal = ref();
const [registerNotSchool, { openModal: openModal1 }] = useModal();
/** const labelCol = reactive({
* 新增事件 xs: {span: 24},
*/ sm: {span: 7},
function handleAdd() { });
openModal(true, { const wrapperCol = reactive({
isUpdate: false, xs: {span: 24},
showFooter: true, sm: {span: 16},
}); });
const {createMessage} = useMessage();
//
const toolbarConfig = reactive({
// add remove clearSelection
btn: ['add', 'save', 'remove', 'clearSelection'],
});
const subToolbarConfig = reactive({
// add remove clearSelection
btn: ['add','remove'],
});
//
const { onExportXls, onImportXls } = useListPage({
tableProps:{
title: '院校招录专业表',
canResize:false,
},
importConfig:{
url: getImportUrl,
success: handleSuccess
} }
/** });
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
}
]
}
/**
* 成功回调
*/
function handleSuccess() {
loadData();
}
//
const loading = ref(false);
//
const queryParam = reactive({
schoolCode: '',//
schoolName:'',
})
//
const pagination = reactive({
//
current: 1,
//
pageSize: 10,
//
pageSizeOptions: ['10', '20', '30', '100', '200'],
// 0
total: 0,
});
//
const selectedRows = ref<Recordable[]>([]);
//
const subTable = reactive({
currentRowId: null,
loading: false,
pagination: { current: 1, pageSize: 0, pageSizeOptions: ['100', '200'], total: 0 },
selectedRows: [],
dataSource: [] as any,
dataSource2: [] as any,
columns: [
{
title: '院校代码',
align: "center",
key: 'schoolCode',
type: JVxeTypes.input,
},{
title: '学校名称',
align: "center",
key: 'schoolName',
type: JVxeTypes.input
}
],
flag:false
});
//
const dataSource = ref<Recordable[]>([]);
//
const columns = tableColumns;
loadData();
async function searchQuery() {
pagination.current = 1
loadData()
}
async function searchReset() {
pagination.current = 1
queryParam.schoolCode = ''
queryParam.schoolName = ''
loadData()
}
//
async function loadData() {
loading.value = true;
//
await defHttp
.get({
//
url: getData,
//
params: {
schoolCode: queryParam.schoolCode,
schoolName: queryParam.schoolName,
pageNo: pagination.current,
pageSize: pagination.pageSize,
},
})
.then((result) => {
// total
pagination.total = result.total;
// dataSource
dataSource.value = result.records;
//
selectedRows.value = [];
})
.finally(() => {
// loading
loading.value = false;
});
}
//
function handleTableSave({$table, target}) {
//
$table.validate().then((errMap) => {
//
if (!errMap) {
//
let tableData = target.getTableData();
console.log('当前保存的数据是:', tableData);
//
let newData = target.getNewData();
console.log('-- 新增的数据:', newData);
//
let deleteData = target.getDeleteData();
console.log('-- 删除的数据:', deleteData);
//
loading.value = true;
defHttp
.post({
url: saveAll,
params: tableData,
})
.then(() => {
createMessage.success(`保存成功!`);
})
.finally(() => {
loading.value = false;
});
}
});
}
//
function handleTableRemove(event) {
// event.deleteRows
console.log('待删除的数据: ', event.deleteRows);
// IDID
let deleteIds = event.deleteRows.map((row) => row.id);
console.log('待删除的数据ids: ', deleteIds);
//
loading.value = true;
window.setTimeout(() => {
defHttp
.delete({
url: deleteBatch, data: {ids: deleteIds.join(',')}
}, {joinParamsToUrl: true})
.then((res) => {
createMessage.success('删除成功');
//// confirmRemove()
event.confirmRemove();
})
.finally(() => {
loading.value = false;
});
}, 1000);
}
function handleValueChange(event) {
console.log('handleValueChange.event: ', event);
let {$table, row, column} = event;
let field = column.property;
console.log(row)
handleEditClosed(event)
}
//
function handleEditClosed(event) {
let {$table, row, column} = event;
let field = column.property;
//
if ($table.isUpdateByRow(row, field)) {
//
$table.validate(row).then((errMap) => {
//
if (!errMap) {
//
let hideLoading = createMessage.loading(`正在保存"${column.title}"`, 0);
console.log('即时保存数据:', row);
defHttp
.put({
url: saveRow,
params: row,
})
.then((res) => {
createMessage.success(`"${column.title}"保存成功!`);
//
$table.reloadRow(row, null, field);
})
.finally(() => {
hideLoading();
});
}
});
}
}
//
function handlePageChange(event) {
//
pagination.current = event.current;
pagination.pageSize = event.pageSize;
//
loadData();
}
//
function handleSelectRowChange(event) {
selectedRows.value = event.selectedRows;
}
function onLookRowHistoryScore(props) {
// createMessage.success('');
// console.log(': ', { props });
}
//
function loadSubData(row) {
if (row) {
//
// if (subTable.currentRowId === row.id) {
// return true;
// }
subTable.currentRowId = row.id;
subTable.loading = true;
defHttp
.get({
url: '/yx/yxSchoolChild/list',
params: {
pageNo: 1,
pageSize: 30,
schoolId: row.id
},
})
.then((result) => {
// dataSource
subTable.dataSource = result.records;
subTable.dataSource2 = result.records;
})
.finally(() => {
// loading
subTable.flag = true;
subTable.loading = false;
});
return true;
} else {
return false;
}
}
function handleSubTableRemove(event){
// event.deleteRows
console.log('待删除的数据: ', event.deleteRows);
// IDID
let deleteIds = event.deleteRows.map((row) => row.id);
console.log('待删除的数据ids: ', deleteIds);
//
loading.value = true;
window.setTimeout(() => {
defHttp
.delete({
url: '/yx/yxSchoolChild/deleteBatch', data: {ids: deleteIds.join(',')}
}, {joinParamsToUrl: true})
.then((res) => {
createMessage.success('删除成功');
//// confirmRemove()
event.confirmRemove();
})
.finally(() => {
loading.value = false;
});
}, 1000);
}
//
function handleSubEditClosed(event) {
let {$table, row, column} = event;
let field = column.property;
console.log(event)
//
if(subTable.dataSource2){
let index = 0
for(let i = 0;i<subTable.dataSource2.length;i++){
let dd = subTable.dataSource2[i]
if(dd['id'] == row['id'] && dd[field] == row[field]){
index = i
return false
}
}
//
$table.validate(row).then((errMap) => {
//
if (!errMap) {
row.schoolId = subTable.currentRowId as any
if(row.id && row.id.includes('row')){
row.id = null
}
//
let hideLoading = createMessage.loading(`正在保存"${column.title}"`, 0);
console.log('即时保存数据:', row);
defHttp
.put({
url: '/yx/yxSchoolChild/edit',
params: row,
})
.then((res) => {
createMessage.success(`"${column.title}"保存成功!`);
//
$table.reloadRow(row, null, field);
loadSubData({id:subTable.currentRowId})
// subTable.dataSource[index] = row
// subTable.dataSource2 = subTable.dataSource
})
.finally(() => {
hideLoading();
});
}
});
}
}
/**
* 导出xls
* @param name
* @param url
*/
async function exportXls(isXlsx = false) {
let name = ''
let selections = ''
if (selectedRows.value) {
selectedRows.value.forEach(i=>{
selections+=i.id+","
})
console.log(selectedRows.value)
}else{
createMessage.warning('院校暂不支持大量导出,请选择指定院校导出');
return;
}
loading.value = true;
const data = await defHttp.get({ url: getExportUrl, params: {selections:selections}, responseType: 'blob', timeout: 60000 }, { isTransformResponse: false });
if (!data) {
createMessage.warning('文件下载失败');
return;
}
if (!name || typeof name != 'string') {
name = '导出文件';
}
let blobOptions = { type: 'application/vnd.ms-excel' };
let fileSuffix = '.xls';
if (isXlsx === true) {
blobOptions['type'] = XLSX_MIME_TYPE;
fileSuffix = XLSX_FILE_SUFFIX;
}
loading.value = false;
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data], blobOptions), name + fileSuffix);
} else {
let url = window.URL.createObjectURL(new Blob([data], blobOptions));
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', name + fileSuffix);
document.body.appendChild(link);
link.click();
document.body.removeChild(link); //
window.URL.revokeObjectURL(url); //blob
}
}
/**
* 编辑事件
*/
function handleEdit(props: any) {
subTable.flag = false
registerModal.value.disableSubmit = false;
registerModal.value.edit(props.row);
}
function handleShowSub(props:any){
loadSubData(props.row)
}
async function searchNotHasSchool(){
await defHttp
.get({
//
url: queryNotHasSchool,
//
params: {
},
})
.then((result) => {
let list = []
for (let i = 0; i < result.length; i++) {
list.push({
schoolCode: result[i], key : i
});
}
state.notSchoolList = list
showModal()
})
.finally(() => {
// loading
});
}
const open = ref<boolean>(false);
const state = reactive({
notSchoolList:[],
columns:[{
title: '院校代码',
dataIndex: 'schoolCode',
key: 'name',
}]
})
function showModal(){
open.value = true;
};
function handleOk(e){
console.log(e);
open.value = false;
};
// function handleEdit(record: Recordable) {
// registerModal.value.disableSubmit = false;
// registerModal.value.edit(record);
// }
</script> </script>
<style scoped> <style scoped></style>
</style>

View File

@ -0,0 +1,217 @@
<template>
<div>
<!--查询区域-->
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row :gutter="24">
</a-row>
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template #htmlSlot="{text}">
<div v-html="text"></div>
</template>
<!--省市区字段回显插槽-->
<template #pcaSlot="{text}">
{{ getAreaTextByCode(text) }}
</template>
<template #fileSlot="{text}">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
</template>
</BasicTable>
<!-- 表单区域 -->
<YxSchoolModal ref="registerModal" @success="handleSuccess"></YxSchoolModal>
</div>
</template>
<script lang="ts" name="yx-yxSchool" setup>
import { ref, reactive } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns2 } from './YxSchool.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './YxSchool.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import YxSchoolModal from './components/YxSchoolModal.vue'
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: '学校信息表',
api: list,
columns2,
canResize:false,
useSearchForm: false,
actionColumn: {
width: 120,
fixed: 'right',
},
beforeFetch: (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name: "学校信息表",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
});
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const labelCol = reactive({
xs: { span: 24 },
sm: { span: 7 },
});
const wrapperCol = reactive({
xs: { span: 24 },
sm: { span: 16 },
});
/**
* 新增事件
*/
function handleAdd() {
registerModal.value.disableSubmit = false;
registerModal.value.add();
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
registerModal.value.disableSubmit = false;
registerModal.value.edit(record);
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
registerModal.value.disableSubmit = true;
registerModal.value.edit(record);
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
}
]
}
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust{
width: calc(50% - 15px);
min-width: 100px !important;
}
.query-group-split-cust{
width: 30px;
display: inline-block;
text-align: center
}
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<BasicModal v-bind="$attrs" @register="register" title="缺失院校" @visible-change="handleVisibleChange">
<div class="pt-3px pr-3px">
<a-table :columns="columns" :data-source="dataList" :hideOnSinglePage="true" />
<BasicForm @register="registerForm" :model="model" />
</div>
</BasicModal>
</template>
<script lang="ts">
import { defineComponent, ref, nextTick } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
const columns = [
{
title: '院校代码',
dataIndex: 'schoolCode',
key: 'name',
},
];
const dataList = [{
key: '1',
schoolCode: '胡彦斌',
},
{
key: '2',
schoolCode: '胡彦祖',
},];
const schemas: FormSchema[] = [];
export default defineComponent({
components: { BasicModal, BasicForm },
props: {
userData: { type: Object },
},
setup(props) {
const modelRef = ref({});
const [
registerForm,
{
// setFieldsValue,
// setProps
},
] = useForm({
labelWidth: 120,
schemas,
showActionButtonGroup: false,
actionColOptions: {
span: 24,
},
});
const [register] = useModalInner((data) => {
data && onDataReceive(data);
});
function onDataReceive(data) {
if(data.data){
for (let i = 0; i < data.data.length; i++) {
dataList.push({
schoolCode: data.data[i], key : i
});
}
console.log(dataList);
modelRef.value = { dataList: dataList };
}
// setProps({
// model:{ field2: data.data, field1: data.info }
// })
}
function handleVisibleChange(v) {
v && props.userData && nextTick(() => onDataReceive(props.userData));
}
return { columns, dataList, register, schemas, registerForm, model: modelRef, handleVisibleChange };
},
});
</script>

View File

@ -1,70 +1,327 @@
<template> <template>
<div style="min-height: 400px"> <a-spin :spinning="confirmLoading">
<BasicForm @register="registerForm"></BasicForm> <a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol">
<div style="width: 100%;text-align: center" v-if="!formDisabled"> <a-row>
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary"> </a-button> <a-col :span="24">
</div> <a-form-item label="学校名称" v-bind="validateInfos.schoolName">
</div> <a-input v-model:value="formData.schoolName" placeholder="请输入学校名称" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="旧院校名称" v-bind="validateInfos.oldSchoolName">
<a-input v-model:value="formData.oldSchoolName" placeholder="请输入旧院校名称" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="官方网址" v-bind="validateInfos.schoolWebsiteAddress">
<a-input v-model:value="formData.schoolWebsiteAddress" placeholder="请输入官方网址" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="学校电话" v-bind="validateInfos.schoolPhone">
<a-input v-model:value="formData.schoolPhone" placeholder="请输入学校电话" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="电子邮箱" v-bind="validateInfos.schoolEmail">
<a-input v-model:value="formData.schoolEmail" placeholder="请输入电子邮箱" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="学校图标" v-bind="validateInfos.schoolIcon">
<j-image-upload v-model:value="formData.schoolIcon" :disabled="disabled"></j-image-upload>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="办学日期" v-bind="validateInfos.schoolOpenDate">
<a-input v-model:value="formData.schoolOpenDate" placeholder="请输入办学日期" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="省份" v-bind="validateInfos.province">
<a-input v-model:value="formData.province" placeholder="请输入省份" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="城市" v-bind="validateInfos.city">
<a-input v-model:value="formData.city" placeholder="请输入城市" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="区域" v-bind="validateInfos.area">
<a-input v-model:value="formData.area" placeholder="请输入区域" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="详细地址" v-bind="validateInfos.street">
<a-input v-model:value="formData.street" placeholder="请输入详细地址" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="隶属于" v-bind="validateInfos.affiliation">
<a-input v-model:value="formData.affiliation" placeholder="请输入隶属于" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="办学性质" v-bind="validateInfos.schoolNature">
<a-input v-model:value="formData.schoolNature" placeholder="请输入办学性质" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="院校类型" v-bind="validateInfos.institutionType">
<a-input v-model:value="formData.institutionType" placeholder="请输入院校类型" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="办学类型" v-bind="validateInfos.schoolType">
<a-input v-model:value="formData.schoolType" placeholder="请输入办学类型" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="学生人数" v-bind="validateInfos.studentNum">
<a-input v-model:value="formData.studentNum" placeholder="请输入学生人数" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="基本信息" v-bind="validateInfos.baseInfo">
<j-editor v-model:value="formData.baseInfo" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="标签" v-bind="validateInfos.tags">
<a-input v-model:value="formData.tags" placeholder="请输入标签" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="学校批次" v-bind="validateInfos.schoolBatch">
<a-input v-model:value="formData.schoolBatch" placeholder="请输入学校批次" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="985工程" v-bind="validateInfos.is985">
<a-input-number v-model:value="formData.is985" placeholder="请输入985工程" style="width: 100%" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="211工程" v-bind="validateInfos.is211">
<a-input-number v-model:value="formData.is211" placeholder="请输入211工程" style="width: 100%" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="强基计划" v-bind="validateInfos.isStrengthen">
<a-input-number v-model:value="formData.isStrengthen" placeholder="请输入强基计划" style="width: 100%" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="一流大学" v-bind="validateInfos.yldx">
<a-input v-model:value="formData.yldx" placeholder="请输入一流大学" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="国重/省重" v-bind="validateInfos.gzsz">
<a-input v-model:value="formData.gzsz" placeholder="请输入国重/省重" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="保研率" v-bind="validateInfos.byl">
<a-input v-model:value="formData.byl" placeholder="请输入保研率" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="国家特色专业" v-bind="validateInfos.gjtszy">
<a-input v-model:value="formData.gjtszy" placeholder="请输入国家特色专业" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="省特色专业" v-bind="validateInfos.stszy">
<a-input v-model:value="formData.stszy" placeholder="请输入省特色专业" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否国重点" v-bind="validateInfos.gzd">
<a-input v-model:value="formData.gzd" placeholder="请输入是否国重点" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="世界一流" v-bind="validateInfos.sjyl">
<a-input v-model:value="formData.sjyl" placeholder="请输入世界一流" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否双一流" v-bind="validateInfos.sfsyl">
<a-input v-model:value="formData.sfsyl" placeholder="请输入是否双一流" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="占地面积(亩)" v-bind="validateInfos.are">
<a-input-number v-model:value="formData.are" placeholder="请输入占地面积(亩)" style="width: 100%" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="男生占比" v-bind="validateInfos.maleRatio">
<a-input-number v-model:value="formData.maleRatio" placeholder="请输入男生占比" style="width: 100%" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="女生占比" v-bind="validateInfos.femaleRatio">
<a-input-number v-model:value="formData.femaleRatio" placeholder="请输入女生占比" style="width: 100%" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否是艺术" v-bind="validateInfos.isYs">
<a-input-number v-model:value="formData.isYs" placeholder="请输入是否是艺术" style="width: 100%" :disabled="disabled"/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-spin>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import {BasicForm, useForm} from '/@/components/Form/index'; import { ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted } from 'vue';
import {computed, defineComponent} from 'vue'; import { defHttp } from '/@/utils/http/axios';
import {defHttp} from '/@/utils/http/axios'; import { useMessage } from '/@/hooks/web/useMessage';
import { propTypes } from '/@/utils/propTypes'; import JImageUpload from '/@/components/Form/src/jeecg/components/JImageUpload.vue';
import {getBpmFormSchema} from '../YxSchool.data'; import JEditor from '/@/components/Form/src/jeecg/components/JEditor.vue';
import {saveOrUpdate} from '../YxSchool.api'; import { getValueType } from '/@/utils';
import { saveOrUpdate } from '../YxSchool.api';
import { Form } from 'ant-design-vue';
export default defineComponent({ const props = defineProps({
name: "YxSchoolForm", formDisabled: { type: Boolean, default: false },
components:{ formData: { type: Object, default: ()=>{} },
BasicForm formBpm: { type: Boolean, default: true }
}, });
props:{ const formRef = ref();
formData: propTypes.object.def({}), const useForm = Form.useForm;
formBpm: propTypes.bool.def(true), const emit = defineEmits(['register', 'ok']);
}, const formData = reactive<Record<string, any>>({
setup(props){ id: '',
const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({ schoolName: '',
labelWidth: 150, oldSchoolName: '',
schemas: getBpmFormSchema(props.formData), schoolWebsiteAddress: '',
showActionButtonGroup: false, schoolPhone: '',
baseColProps: {span: 24} schoolEmail: '',
}); schoolIcon: '',
schoolOpenDate: '',
province: '',
city: '',
area: '',
street: '',
affiliation: '',
schoolNature: '',
institutionType: '',
schoolType: '',
studentNum: '',
baseInfo: '',
tags: '',
schoolBatch: '',
is985: undefined,
is211: undefined,
isStrengthen: undefined,
yldx: '',
gzsz: '',
byl: '',
gjtszy: '',
stszy: '',
gzd: '',
sjyl: '',
sfsyl: '',
are: undefined,
maleRatio: undefined,
femaleRatio: undefined,
isYs: undefined,
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//
const validatorRules = {
};
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: true });
const formDisabled = computed(()=>{ //
if(props.formData.disabled === false){ const disabled = computed(()=>{
return false; if(props.formBpm === true){
} if(props.formData.disabled === false){
return true; return false;
}); }else{
return true;
}
}
return props.formDisabled;
});
let formData = {};
const queryByIdUrl = '/yx/yxSchool/queryById';
async function initFormData(){
let params = {id: props.formData.dataId};
const data = await defHttp.get({url: queryByIdUrl, params});
formData = {...data}
//
await setFieldsValue(formData);
//
await setProps({disabled: formDisabled.value})
}
async function submitForm() { /**
let data = getFieldsValue(); * 新增
let params = Object.assign({}, formData, data); */
console.log('表单数据', params) function add() {
await saveOrUpdate(params, true) edit({});
} }
initFormData(); /**
* 编辑
return { */
registerForm, function edit(record) {
formDisabled, nextTick(() => {
submitForm, resetFields();
} //
} Object.assign(formData, record);
}); });
}
/**
* 提交数据
*/
async function submitForm() {
//
await validate();
confirmLoading.value = true;
const isUpdate = ref<boolean>(false);
//
let model = formData;
if (model.id) {
isUpdate.value = true;
}
//
for (let data in model) {
//
if (model[data] instanceof Array) {
let valueType = getValueType(formRef.value.getProps, data);
//
if (valueType === 'string') {
model[data] = model[data].join(',');
}
}
}
await saveOrUpdate(model, isUpdate.value)
.then((res) => {
if (res.success) {
createMessage.success(res.message);
emit('ok');
} else {
createMessage.warning(res.message);
}
})
.finally(() => {
confirmLoading.value = false;
});
}
defineExpose({
add,
edit,
submitForm,
});
</script> </script>
<style lang="less" scoped>
.antd-modal-form {
min-height: 500px !important;
overflow-y: auto;
padding: 24px 24px 24px 24px;
}
</style>

View File

@ -1,66 +1,75 @@
<template> <template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit"> <a-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<BasicForm @register="registerForm"/> <YxSchoolForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></YxSchoolForm>
</BasicModal> </a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {ref, computed, unref} from 'vue'; import { ref, nextTick, defineExpose } from 'vue';
import {BasicModal, useModalInner} from '/@/components/Modal'; import YxSchoolForm from './YxSchoolForm.vue'
import {BasicForm, useForm} from '/@/components/Form/index';
import {formSchema} from '../YxSchool.data'; const title = ref<string>('');
import {saveOrUpdate} from '../YxSchool.api'; const width = ref<number>(800);
// Emits const visible = ref<boolean>(false);
const emit = defineEmits(['register','success']); const disableSubmit = ref<boolean>(false);
const isUpdate = ref(true); const registerForm = ref();
// const emit = defineEmits(['register', 'success']);
const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
//labelWidth: 150, /**
schemas: formSchema, * 新增
showActionButtonGroup: false, */
baseColProps: {span: 24} function add() {
title.value = '新增';
visible.value = true;
nextTick(() => {
registerForm.value.add();
}); });
// }
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
// /**
await resetFields(); * 编辑
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter}); * @param record
isUpdate.value = !!data?.isUpdate; */
if (unref(isUpdate)) { function edit(record) {
// title.value = disableSubmit.value ? '详情' : '编辑';
await setFieldsValue({ visible.value = true;
...data.record, nextTick(() => {
}); registerForm.value.edit(record);
}
//
setProps({ disabled: !data?.showFooter })
}); });
// }
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
// /**
async function handleSubmit(v) { * 确定按钮点击事件
try { */
let values = await validate(); function handleOk() {
setModalProps({confirmLoading: true}); registerForm.value.submitForm();
// }
await saveOrUpdate(values, isUpdate.value);
// /**
closeModal(); * form保存回调事件
// */
emit('success'); function submitCallback() {
} finally { handleCancel();
setModalProps({confirmLoading: false}); emit('success');
} }
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
}
defineExpose({
add,
edit,
disableSubmit,
});
</script> </script>
<style lang="less" scoped> <style>
/** 时间和数字输入框样式 */ /**隐藏样式-modal确定按钮 */
:deep(.ant-input-number){ .jee-hidden {
width: 100% display: none !important;
} }
:deep(.ant-calendar-picker){
width: 100%
}
</style> </style>

View File

@ -51,10 +51,23 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="3">
<a-form-item label="数据状态">
<a-select v-model:value="queryParam.state" show-search allow-clear placeholder="请选择状态">
<a-select-option value="">请选择</a-select-option>
<a-select-option value="0">停招</a-select-option>
<a-select-option value="1">招生</a-select-option>
<a-select-option value="2">新增</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :span="12">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button> <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="exportXls" style="margin: 8px">导出</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button> <a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="exportXls" style="margin: 8px">导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls" style="margin-left: 8px">导入</j-upload-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
@ -67,8 +80,8 @@
<JVxeTable <JVxeTable
toolbar toolbar
:toolbarConfig="toolbarConfig" :toolbarConfig="toolbarConfig"
rowNumber
rowSelection rowSelection
clickRowShowSubForm
keepSource keepSource
asyncRemove asyncRemove
:height="500" :height="500"
@ -81,7 +94,35 @@
@edit-closed="handleEditClosed" @edit-closed="handleEditClosed"
@pageChange="handlePageChange" @pageChange="handlePageChange"
@selectRowChange="handleSelectRowChange" @selectRowChange="handleSelectRowChange"
/> >
<template #myAction="props">
<a @click="onLookRowHistoryScore(props)">历年分数</a>
<!-- <a-divider type="vertical" />-->
<!-- <Popconfirm title="确定删除吗?" @confirm="onDeleteRow(props)">-->
<!-- <a>删除</a>-->
<!-- </Popconfirm>-->
</template>
<!-- 子表单 -->
<template #subForm="{ row }">
<template v-if="loadSubData(row)">
<JVxeTable
toolbar
:title="'标题'"
:toolbarConfig="subToolbarConfig"
rowSelection
ref="subFormTable"
height="auto"
:max-height="350"
:loading="subTable.loading"
:columns="subTable.columns"
:dataSource="subTable.dataSource"
@edit-closed="handleHistoryScoreEditClosed"
/>
</template>
</template>
</JVxeTable>
</a-card> </a-card>
</template> </template>
@ -93,6 +134,10 @@ import {JVxeColumn, JVxeTypes} from '/@/components/jeecg/JVxeTable/types';
import {useMessage} from '/@/hooks/web/useMessage'; import {useMessage} from '/@/hooks/web/useMessage';
import { useListPage } from '/@/hooks/system/useListPage'; import { useListPage } from '/@/hooks/system/useListPage';
import {XLSX_FILE_SUFFIX, XLSX_MIME_TYPE} from "@/hooks/system/useMethods"; import {XLSX_FILE_SUFFIX, XLSX_MIME_TYPE} from "@/hooks/system/useMethods";
import {columnsN } from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.data";
import { getImportUrl } from "@/views/yx/yxSchoolMajor/YxSchoolMajor.api";
import {getData as getHistoryData,saveRow as saveHistoryRow} from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api";
const labelCol = reactive({ const labelCol = reactive({
xs: {span: 24}, xs: {span: 24},
sm: {span: 7}, sm: {span: 7},
@ -107,22 +152,29 @@ const toolbarConfig = reactive({
// add remove clearSelection // add remove clearSelection
btn: ['add', 'save', 'remove', 'clearSelection'], btn: ['add', 'save', 'remove', 'clearSelection'],
}); });
const subToolbarConfig = reactive({
// add remove clearSelection
btn: ['add'],
});
// //
const { onExportXls, onImportXls } = useListPage({ const { onExportXls, onImportXls } = useListPage({
designScope: 'basic-table', tableProps:{
tableProps: { title: '院校招录专业表',
showActionColumn: false, canResize:false,
useSearchForm: false,
},
exportConfig: {
name: '示例列表',
url: '/test/jeecgDemo/exportXls',
},
importConfig: {
url: '/test/jeecgDemo/importExcel',
}, },
importConfig:{
url: getImportUrl,
success: handleSuccess
}
}); });
/**
* 成功回调
*/
function handleSuccess() {
loadData();
}
// //
const loading = ref(false); const loading = ref(false);
// //
@ -132,6 +184,7 @@ const queryParam = reactive({
majorType: '',// majorType: '',//
category: '',// category: '',//
batch:'',// batch:'',//
state:'',//
}) })
// //
const pagination = reactive({ const pagination = reactive({
@ -146,11 +199,50 @@ const pagination = reactive({
}); });
// //
const selectedRows = ref<Recordable[]>([]); const selectedRows = ref<Recordable[]>([]);
//
const subTable = reactive({
currentRowId: null,
loading: false,
pagination: { current: 1, pageSize: 0, pageSizeOptions: ['100', '200'], total: 0 },
selectedRows: [],
dataSource: [] as any,
dataSource2: [] as any,
columns: columnsN,
});
// //
const dataSource = ref<Recordable[]>([]); const dataSource = ref<Recordable[]>([]);
// //
const columns = ref<JVxeColumn[]>([ const columns = ref<JVxeColumn[]>([
/*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/ /*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/
{
title: '操作',
key: 'action',
type: JVxeTypes.slot,
fixed: 'right',
minWidth: 120,
align: 'center',
slotName: 'myAction',
},
{
//
title: '数据状态',
// key
key: 'state',
//
width: 100,
// typeinput
type: JVxeTypes.select,
//
options: [
{ title: '停招', value: '0' },
{ title: '招生', value: '1' },
{ title: '新增', value: '2' }
],
// allowInput: true,
allowSearch: true,
placeholder: '请选择',
},
{ {
// //
title: '学校代码', title: '学校代码',
@ -323,6 +415,7 @@ enum Api {
saveAll = '/yx/yxSchoolMajor/saveBatch', saveAll = '/yx/yxSchoolMajor/saveBatch',
deleteBatch = '/yx/yxSchoolMajor/deleteBatch', deleteBatch = '/yx/yxSchoolMajor/deleteBatch',
exportXls = '/yx/yxSchoolMajor/exportXls', exportXls = '/yx/yxSchoolMajor/exportXls',
importExcel = '/yx/yxSchoolMajor/importExcel',
} }
loadData(); loadData();
@ -339,6 +432,7 @@ async function searchReset() {
queryParam.majorType = '' queryParam.majorType = ''
queryParam.category = '' queryParam.category = ''
queryParam.batch = '' queryParam.batch = ''
queryParam.state = ''
loadData() loadData()
} }
@ -357,6 +451,7 @@ async function loadData() {
majorType:queryParam.majorType, majorType:queryParam.majorType,
category:queryParam.category, category:queryParam.category,
batch:queryParam.batch, batch:queryParam.batch,
state:queryParam.state,
pageNo: pagination.current, pageNo: pagination.current,
pageSize: pagination.pageSize, pageSize: pagination.pageSize,
}, },
@ -477,6 +572,94 @@ function handleSelectRowChange(event) {
selectedRows.value = event.selectedRows; selectedRows.value = event.selectedRows;
} }
function onLookRowHistoryScore(props) {
// createMessage.success('');
// console.log(': ', { props });
}
//
function loadSubData(row) {
if (row) {
//
if (subTable.currentRowId === row.id) {
return true;
}
subTable.currentRowId = row.id;
subTable.loading = true;
defHttp
.get({
url: getHistoryData,
params: {
pageNo: 1,
pageSize: 30,
schoolCode: row.schoolCode,
majorName:row.majorName,
category:row.category,
batch:row.batch
},
})
.then((result) => {
// dataSource
subTable.dataSource = result.records;
subTable.dataSource2 = result.records;
})
.finally(() => {
// loading
subTable.loading = false;
});
return true;
} else {
return false;
}
}
//
function handleHistoryScoreEditClosed(event) {
let {$table, row, column} = event;
let field = column.property;
console.log(event)
//
if(subTable.dataSource2){
let index = 0
for(let i = 0;i<subTable.dataSource2.length;i++){
let dd = subTable.dataSource2[i]
if(dd['id'] == row['id'] && dd[field] == row[field]){
index = i
return false
}
}
//
$table.validate(row).then((errMap) => {
//
if (!errMap) {
//
let hideLoading = createMessage.loading(`正在保存"${column.title}"`, 0);
console.log('即时保存数据:', row);
defHttp
.put({
url: saveHistoryRow,
params: row,
})
.then((res) => {
createMessage.success(`"${column.title}"保存成功!`);
//
$table.reloadRow(row, null, field);
subTable.dataSource[index] = row
subTable.dataSource2 = subTable.dataSource
})
.finally(() => {
hideLoading();
});
}
});
}
}
/** /**
* 导出xls * 导出xls
* @param name * @param name
@ -522,3 +705,4 @@ async function exportXls(isXlsx = false) {
</script> </script>
<style scoped></style> <style scoped></style>

View File

@ -27,6 +27,11 @@ export const columns: BasicColumn[] = [
return !text?"":(text.length>10?text.substr(0,10):text) return !text?"":(text.length>10?text.substr(0,10):text)
}, },
},*/ },*/
{
title: '所属应用',
align: 'center',
dataIndex: 'programType',
},
{ {
title: '对应商品', title: '对应商品',
align: "center", align: "center",
@ -63,6 +68,11 @@ export const formSchema: FormSchema[] = [
field: 'validTime', field: 'validTime',
component: 'InputNumber', component: 'InputNumber',
}, },
{
label: '所属应用',
field: 'programType',
component: 'Input',
},
/*{ /*{
label: '有效日期', label: '有效日期',
field: 'validDate', field: 'validDate',

View File

@ -22,6 +22,16 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="3">
<a-form-item label="所属应用" name="skuCode">
<a-select v-model:value="queryParam.programType" show-search allow-clear
placeholder="请选择">
<a-select-option value="">请选择</a-select-option>
<a-select-option value="艺体志愿宝">艺体志愿宝</a-select-option>
<a-select-option value="体育志愿宝">体育志愿宝</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="4"> <a-col :span="4">
<a-form-item label="有效时长(天)"> <a-form-item label="有效时长(天)">
<a-input type="number" v-model:value="queryParam.validTime" placeholder="请输入有效时长" <a-input type="number" v-model:value="queryParam.validTime" placeholder="请输入有效时长"
@ -244,6 +254,9 @@ function searchQuery() {
if (queryParam.cardNum) { if (queryParam.cardNum) {
queryParam2.cardNum = '*'+queryParam.cardNum+'*' queryParam2.cardNum = '*'+queryParam.cardNum+'*'
} }
if(queryParam.programType){
queryParam2.programType = queryParam.programType
}
queryParam2.skuCode = queryParam.skuCode queryParam2.skuCode = queryParam.skuCode
queryParam2.validTime = queryParam.validTime queryParam2.validTime = queryParam.validTime
reload(); reload();
@ -259,6 +272,8 @@ function searchReset() {
queryParam2.skuCode='' queryParam2.skuCode=''
queryParam.validTime='' queryParam.validTime=''
queryParam2.validTime='' queryParam2.validTime=''
queryParam.programType=''
queryParam2.programType = ''
selectedRowKeys.value = []; selectedRowKeys.value = [];
// //
reload(); reload();