发言人顺序

This commit is contained in:
z9130 2024-09-29 14:38:52 +08:00
parent 68432d4d68
commit 15595b93b9
19 changed files with 749 additions and 285 deletions

View File

@ -143,7 +143,7 @@
},
"debug.onTaskErrors": "debugAnyway",
"diffEditor.ignoreTrimWhitespace": false,
"diffEditor.ignoreTrimWhitespace": true,
"npm.packageManager": "pnpm",
"css.validate": false,

View File

@ -27,8 +27,6 @@ const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
@ -74,9 +72,6 @@ function handleDelete(row) {
message.success('删除成功');
triggerProxy('reload');
},
onCancel() {
console.log('Cancel');
},
});
}
@ -115,8 +110,7 @@ onMounted(() => {
const searchForm = ref({
...getFormSchema(),
onSearch(context: any) {
console.log(searchRef.value);
onSearch(_context: any) {
triggerProxy('reload');
},
});

View File

@ -28,14 +28,7 @@ export function getFormSchema(params: any = {}) {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return <span>{form.contractName}</span>;
},
disabled: true,
},
},
reportNo: {
@ -46,14 +39,7 @@ export function getFormSchema(params: any = {}) {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return <span>{form.reportNo}</span>;
},
disabled: true,
},
},
ctrType: {
@ -63,26 +49,13 @@ export function getFormSchema(params: any = {}) {
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
class: 'min-w-[180px]',
dict: dict({
async getData({ form = {}, getComponentRef }) {
return filterContractTypes(contractTypeData, '-1');
},
}),
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
const data = filterContractTypes(contractTypeData, '-1');
for (const item of data) {
if (item.value === form.ctrType) {
return <span>{item.label}</span>;
}
}
return <span></span>;
},
disabled: true,
},
},
ctrTwoType: {
@ -92,7 +65,7 @@ export function getFormSchema(params: any = {}) {
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
class: 'min-w-[180px]',
dict: dict({
async getData({ form = {} }) {
if (form.ctrType) {
@ -101,28 +74,18 @@ export function getFormSchema(params: any = {}) {
return contractTypeData;
},
}),
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
const data = filterContractTypes(contractTypeData, form.ctrType);
for (const item of data) {
if (item.value === form.ctrTwoType) {
return <span>{item.label}</span>;
}
}
return <span></span>;
},
disabled: true,
},
},
ctrThreeType: {
title: '三级类别',
key: 'ctrTwoType',
col: { span: 8 },
render({ form }) {
return <span></span>;
component: {
name: 'a-input',
vModel: 'value',
class: 'min-w-[180px]',
disabled: true,
},
},
budgetSum: {
@ -136,14 +99,7 @@ export function getFormSchema(params: any = {}) {
class: 'w-full',
min: 0,
max: 9999,
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return <span>{form.budgetSum}</span>;
},
disabled: true,
},
},
priceType: {
@ -158,21 +114,7 @@ export function getFormSchema(params: any = {}) {
dict: dict({
data: getDictOptions(DICT_TYPE.contract_currency_unit),
}),
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return (
<span class="mr-2">
{
getDictObj(DICT_TYPE.contract_currency_unit, form.priceType)
?.label
}
</span>
);
},
disabled: true,
},
},
fundAllocation: {
@ -183,25 +125,11 @@ export function getFormSchema(params: any = {}) {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
class: 'min-w-[180px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_fund_flow),
}),
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return (
<span class="mr-2">
{
getDictObj(DICT_TYPE.contract_fund_flow, form.fundAllocation)
?.label
}
</span>
);
},
disabled: true,
},
},
fundDitch: {
@ -212,28 +140,13 @@ export function getFormSchema(params: any = {}) {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
class: 'min-w-[180px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_funding_source),
}),
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return (
<span class="mr-2">
{
getDictObj(DICT_TYPE.contract_funding_source, form.fundDitch)
?.label
}
</span>
);
},
disabled: true,
},
},
frameProtocol: {
title: '框架协议',
key: 'frameProtocol',
@ -244,18 +157,7 @@ export function getFormSchema(params: any = {}) {
dict: dict({
data: getDictOptions(DICT_TYPE.common_whether),
}),
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return (
<span class="mr-2">
{getDictObj(DICT_TYPE.common_whether, form.frameProtocol)?.label}
</span>
);
},
disabled: true,
},
},
frameProtocolCtr: {
@ -269,21 +171,7 @@ export function getFormSchema(params: any = {}) {
dict: dict({
data: getDictOptions(DICT_TYPE.common_whether),
}),
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return (
<span class="mr-2">
{
getDictObj(DICT_TYPE.common_whether, form.frameProtocolCtr)
?.label
}
</span>
);
},
disabled: true,
},
},
organiza: {
@ -294,7 +182,7 @@ export function getFormSchema(params: any = {}) {
name: 'fs-dict-radio',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
class: 'min-w-[180px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_organization_form),
}),

View File

@ -162,6 +162,16 @@ const searchForm = ref({
{{ row.ctrName }}
</span>
</template>
<template #form_fileList="scope">
<a-upload
v-model:file-list="scope.form.fileList"
:before-upload="() => false"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
/>
</template>
</vxe-grid>
</div>
</Page>

View File

@ -34,7 +34,7 @@ export function getTodoColumns(_params: any = {}): VxeGridPropTypes.Columns {
{ field: 'taskName', title: '任务', width: 200 },
{ field: 'createTime', title: '分配时间', width: 150 },
{ field: 'inputDepartName', title: '承办单位/部门', width: 150 },
{ field: 'assignee', title: '承办人', width: 100 },
{ field: 'assigneeName', title: '承办人', width: 100 },
{
field: 'operate',
title: '操作',

View File

@ -31,7 +31,7 @@ export function getUserColumns(_params?: any): VxeGridPropTypes.Columns {
}
export function getFormSchema(params?: any): any {
const { formRef } = params || {};
const { formRef, dictMap } = params || {};
const xGridRef = ref();
/** Hooks - 表格 */
@ -66,8 +66,6 @@ export function getFormSchema(params?: any): any {
}
};
const dictMap: any = {};
return {
col: { span: 24 },
initialForm: {
@ -195,10 +193,7 @@ export function getFormSchema(params?: any): any {
col: { span: 24 },
render({ form }) {
// 注意此处的v-model写法
const options1 = getDictOptions(
DICT_TYPE.contract_authorization_period,
'string',
);
const options1 = dictMap[DICT_TYPE.contract_authorization_period];
return (
<div class="flex">

View File

@ -13,7 +13,7 @@ import {
} from 'ant-design-vue';
import Apis from '#/api';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import { DICT_TYPE, getDictDatasAsync, getDictObj } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
import { logger } from '#/utils/logger';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
@ -45,6 +45,7 @@ const formBinding = ref({
...(({ columns: _, ...rest }) => rest)(
getFormSchema({
formRef,
dictMap: {},
}),
),
});
@ -258,8 +259,14 @@ async function handleSubmit(type) {
}
onMounted(async () => {
const data = await getDictDatasAsync([
DICT_TYPE.contract_authorization_period,
]);
console.log(data);
formBinding.value.columns = getFormSchema({
formRef,
dictMap: data,
}).columns;
const contractReferTypeData: any = await Apis.contractReferType.get_list({

View File

@ -786,15 +786,40 @@ export default {
http.post('/app/biddingResult/save', data),
},
home: {
/** 合同系统/首页待办/已办 待办 */
/** 合同系统/首页待办/已办 首页待办 */
get_todo: (data?: QueryOptions) => http.get('/app/home/todo', data),
/** 合同系统/首页待办/已办 首页已办 */
get_done: (data?: QueryOptions) => http.get('/app/home/done', data),
},
sqConsignPt: {
/** 合同系统/签约授权 签约授权保存 */
post_saveSignMultiEntity: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/saveSignMultiEntity', data),
/** 合同系统/签约授权 签约依据查询 */
/** 合同系统/签约授权 签约授权查询 */
get_SigningaAuthorizationSerch: (data?: QueryOptions) =>
http.get('/app/sqConsignPt/SigningaAuthorizationSerch', data),
/** 合同系统/签约授权 查询单条签约授权数据 */
get_getOne: (data?: QueryOptions) =>
http.get('/app/sqConsignPt/getOne', data),
/** 合同系统/签约授权 签约授权提交 */
post_flowStart: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/flowStart', data),
/** 合同系统/签约授权 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/deletes', data),
},
addressorsort: {
/** 协同办公/会议管理/发言人顺序配置 发言人顺序查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/addressorsort/page', data),
/** 协同办公/会议管理/发言人顺序配置 发言人排序保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/addressorsort/save', data),
/** 协同办公/会议管理/发言人顺序配置 批量保存 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/addressorsort/saveBatch', data),
/** 协同办公/会议管理/发言人顺序配置 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/addressorsort/deletes', data),
},
};

View File

@ -69,6 +69,15 @@ const routes: RouteRecordRaw[] = [
name: 'Meeting',
path: '/meeting',
children: [
{
name: 'MeetingConfig',
path: '/meeting/config',
component: () => import('#/views/meeting/config/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '会议配置',
},
},
{
name: 'MeetingEdit',
path: '/meeting/edit/:id?',

View File

@ -1,71 +1,25 @@
<template>
<Page contentClass="h-full flex flex-col">
<EditModal class="w-[600px] max-w-[80vw]" @success="triggerProxy('reload')" />
<BatchAddModal class="w-[950px] max-w-[80vw]" @success="triggerProxy('reload')" />
<fs-search ref="searchRef" v-bind="searchForm"> </fs-search>
<div class="flex-1 min-h-300px">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleBatchAdd()">
<MdiAdd class="text-lg mr-0.5" />
批量录入
</vben-button>
<vben-button
variant="warning"
:disabled="!selectRow || !selectRow['guid']"
@click="handleUpdate(selectRow)"
>
<MdiUpdate class="text-lg mr-0.5" />
编辑
</vben-button>
<vben-button
variant="destructive"
:disabled="!selectRow || !selectRow['guid']"
@click="handleDelete(selectRow)"
>
<MdiDelete class="text-lg mr-0.5" />
删除
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="text-lg mr-0.5" />
导出
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
</vxe-grid>
</div>
</Page>
</template>
<script setup lang="ts">
import { defineComponent, ref, computed, reactive, onMounted } from 'vue';
import { FsCrud } from '@fast-crud/fast-crud';
import { type VxeGridProps } from 'vxe-table'
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import { MdiAdd, MdiUpdate, MdiDelete, MdiImport, MdiExport, MdiRadioUnchecked, MdiRadioChecked } from '@vben/icons';
import { formSchema, getColumns } from './crud.tsx';
import { dict } from "@fast-crud/fast-crud";
import { getMonthStartAndEnd } from '#/utils/time'
import Apis from '#/api'
import dayjs from 'dayjs';
import { message } from "ant-design-vue";
import { Modal } from 'ant-design-vue';
import { unitComponentProps } from '#/common/unit'
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import DutyPeopleEditModal from './duty-people-edit-modal.vue'
import DutyPeopleBatchAddModal from './duty-people-batch-add-modal.vue'
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useRouter } from 'vue-router'
import { Page, useVbenModal } from '@vben/common-ui';
import {
MdiAdd,
MdiDelete,
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message, Modal } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { formSchema, getColumns } from './crud.tsx';
import DutyPeopleBatchAddModal from './duty-people-batch-add-modal.vue';
import DutyPeopleEditModal from './duty-people-edit-modal.vue';
const router = useRouter();
@ -77,30 +31,37 @@ const [BatchAddModal, batchAddModalApi] = useVbenModal({
connectedComponent: DutyPeopleBatchAddModal,
});
const searchRef = ref()
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: ({ page }) => {
let form = searchRef.value?.formData
return Apis.dutyCount.get_page({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...form } })
}
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: ({ page }) => {
const form = searchRef.value?.formData;
return Apis.dutyCount.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...form,
},
});
},
},
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: true
},
}));
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
}),
);
function handleUpdate(row) {
editModalApi.setData({
@ -113,12 +74,12 @@ function handleUpdate(row) {
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: "是否确认删除该条记录?",
content: '是否确认删除该条记录?',
okType: 'danger',
onOk: async () => {
await Apis.dutyCount.post_deletes({ params: { ids: row['guid'] } })
message.success("删除成功");
triggerProxy("reload");
await Apis.dutyCount.post_deletes({ params: { ids: row.guid } });
message.success('删除成功');
triggerProxy('reload');
},
onCancel() {
console.log('Cancel');
@ -130,15 +91,15 @@ function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
type: 'xlsx',
});
message.success("导出成功");
message.success('导出成功');
}
}
function handleBatchAdd() {
batchAddModalApi.setData({
month:''
month: '',
});
batchAddModalApi.open();
}
@ -158,23 +119,80 @@ function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(() => {
triggerProxy('reload')
})
triggerProxy('reload');
});
let searchParams = reactive({})
let searchParams = reactive({});
const searchForm = ref({
...formSchema(),
onSearch(context: any) {
console.log(searchRef.value)
triggerProxy('reload')
console.log(searchRef.value);
triggerProxy('reload');
},
onReset(context: any) {
searchParams = context.form
searchParams = context.form;
},
});
</script>
<template>
<Page content-class="h-full flex flex-col">
<EditModal
class="w-[600px] max-w-[80vw]"
@success="triggerProxy('reload')"
/>
<BatchAddModal
class="w-[950px] max-w-[80vw]"
@success="triggerProxy('reload')"
/>
<fs-search ref="searchRef" v-bind="searchForm" />
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleBatchAdd()">
<MdiAdd class="mr-0.5 text-lg" />
批量录入
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow.guid"
variant="warning"
@click="handleUpdate(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
编辑
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow.guid"
variant="destructive"
@click="handleDelete(selectRow)"
>
<MdiDelete class="mr-0.5 text-lg" />
删除
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style></style>

View File

@ -1,61 +1,51 @@
<script setup lang="ts">
import { computed, reactive, ref, defineAsyncComponent } from "vue";
import type { VxeGridInstance, VxeGridProps } from "vxe-table";
import { Page, useVbenModal } from "@vben/common-ui";
import { useVxeTable } from "#/hooks/vxeTable";
import dayjs from "dayjs";
import { defineAsyncComponent, ref } from 'vue';
import { Page } from '@vben/common-ui';
// import AutoPeople from "./components/auto-people/AutoPeople.vue";
/** 异步加载的组件,用到的时候再加载组件 */
// -- 1
const AutoPeopleSetting = defineAsyncComponent(() => {
return import("./components/auto-people/auto-people.vue");
return import('./components/auto-people/auto-people.vue');
});
const BasicSettings = defineAsyncComponent(() => {
return import("./components/basic-settings/basic-settings.vue");
return import('./components/basic-settings/basic-settings.vue');
});
const DutyPeopleSettings = defineAsyncComponent(() => {
return import("./components/duty-people/duty-people.vue");
return import('./components/duty-people/duty-people.vue');
});
const DeliveryAddress = defineAsyncComponent(() => {
return import("./components/delivery-address/delivery-address.vue");
return import('./components/delivery-address/delivery-address.vue');
});
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: "xGridRef" });
const formRef: any = ref(null);
const editModalRef = ref();
const recordModalRef = ref();
const tabs = ref([
{
title: "基本配置",
desc: "如用餐补助标准等",
title: '基本配置',
desc: '如用餐补助标准等',
key: 2,
},
{
title: "值班天数",
desc: "出差天数人员管理",
title: '值班天数',
desc: '出差天数人员管理',
key: 3,
},
{
title: "自动订餐",
desc: "自动订餐人员管理",
title: '自动订餐',
desc: '自动订餐人员管理',
key: 1,
},
{
title: "订餐地址",
desc: "用于供用户选择保温派送的地址",
title: '订餐地址',
desc: '用于供用户选择保温派送的地址',
key: 5,
},
]);
const tabInfo = ref(tabs.value[0]);
const searchParams = reactive<any>({});
const today = ref(dayjs().format("YYYY-MM-DD"));
/**
* 切换事件
*/
@ -65,13 +55,16 @@ function handleTabChange(item) {
</script>
<template>
<Page contentClass="h-full">
<Page content-class="h-full">
<a-row class="h-full">
<a-col :span="5" class="min-w-[200px]">
<a-list item-layout="horizontal" :data-source="tabs" size="small">
<a-list :data-source="tabs" item-layout="horizontal" size="small">
<template #renderItem="{ item }">
<a-list-item class="cursor-pointer list-item" :class="{ active: tabInfo.key === item.key }"
@click="handleTabChange(item)">
<a-list-item
:class="{ active: tabInfo.key === item.key }"
class="list-item cursor-pointer"
@click="handleTabChange(item)"
>
<a-list-item-meta>
<template #title>
<span> {{ item.title }}</span>
@ -85,7 +78,7 @@ function handleTabChange(item) {
</a-list>
</a-col>
<a-col :span="19" class="flex flex-col min-w-[700px]">
<a-col :span="19" class="flex min-w-[700px] flex-col">
<AutoPeopleSetting v-if="tabInfo.key === 1" />
<BasicSettings v-if="tabInfo.key === 2" />
<DutyPeopleSettings v-if="tabInfo.key === 3" />

View File

@ -333,7 +333,12 @@ const searchForm = ref({
>
{{ `${row.name}-${row.idNumber}` }}
</p>
<p v-else>{{ row.unit }} ({{ row.children.length || 0 }}人用餐)</p>
<p v-else>
{{ row.unit }}
<span v-if="row.children && row.children.length > 0">
({{ row.children.length }})
</span>
</p>
</template>
</vxe-grid>
</div>

View File

@ -645,7 +645,12 @@ function handleSettlement(type: '0' | '1') {
>
{{ `${row.name}-${row.idNumber}` }}
</span>
<p v-else>{{ row.unit }} ({{ row.children.length || 0 }}人用餐)</p>
<p v-else>
{{ row.unit }}
<span v-if="row.children && row.children.length > 0">
({{ row.children.length }})
</span>
</p>
</template>
</vxe-grid>
</div>

View File

@ -0,0 +1,144 @@
<script lang="tsx" setup>
import { nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
const emit = defineEmits<{
(e: 'success'): void;
}>();
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
connectedComponent: chooseUserModal,
});
const isConfirmLoading = ref(false);
const data = ref({
isUpdate: false,
record: {},
});
const formRef = ref();
const formBinding = ref({
col: { span: 24 },
initialForm: {},
labelCol: { style: { width: '120px' } },
columns: {
// unitId: {
// title: '',
// key: 'unitId',
// col: { span: 12 },
// component: unitComponentProps,
// },
// userName: {
// title: '',
// key: 'userId',
// col: { span: 12 },
// component: {
// name: 'a-input',
// vModel: 'value',
// readOnly: true,
// onClick: () => {
// chooseUserModalApi.open();
// },
// },
// },
name: {
title: '单位/人员名称',
key: 'name',
component: {
name: 'a-input',
vModel: 'value',
readOnly: true,
},
},
sort: {
title: '发言顺序',
key: 'sort',
component: {
name: 'a-input-number',
vModel: 'value',
min: 0,
},
rules: [{ required: true, message: '请输入发言顺序' }],
},
remarks: {
title: '备注',
key: 'remarks',
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
},
},
},
});
const currUser = ref({});
function handleChooseUserRowClick(row) {
formRef.value?.setFormData({
userName: row.label,
});
currUser.value = row;
chooseUserModalApi.close();
}
const [Modal, modalApi] = useVbenModal({
async onOpenChange(isOpen: boolean) {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
nextTick(() => {
formRef.value.setFormData({
...data.value.record,
});
});
}
isConfirmLoading.value = false;
},
async onConfirm() {
isConfirmLoading.value = true;
try {
formRef.value?.submit();
const form = formRef.value.form;
// form.id = form.unitId || currUser.value.ACCOUNT_ID;
// if (!form.id) {
// message.warning('');
// return;
// }
await Apis.addressorsort.post_saveBatch({ data: [form] });
message.success('操作成功');
modalApi.close();
emit('success');
} catch (error) {
logger.error('', error);
} finally {
isConfirmLoading.value = false;
}
},
});
</script>
<template>
<Modal
:confirm-loading="isConfirmLoading"
:loading="isConfirmLoading"
:title="data.isUpdate ? '修改会议发言人顺序' : '新增会议发言人顺序'"
>
<ChooseUserModal class="w-[950px]" @row-click="handleChooseUserRowClick" />
<div v-if="false" class="mb-4 w-full">
<a-alert
message="单位或人员选择其中一个即可,同时存在时,以单位为准"
type="info"
/>
</div>
<fs-form ref="formRef" v-bind="formBinding" />
</Modal>
</template>

View File

@ -0,0 +1,250 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import {
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message, Modal } from 'ant-design-vue';
import Sortable from 'sortablejs';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import addressorSortEditModal from './addressor-sort-edit-modal.vue';
import { getColumns } from './crud';
const [EditModal, editModalApi] = useVbenModal({
connectedComponent: addressorSortEditModal,
});
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
let sortable2: any;
const showHelpTip = ref(false);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
const data = await Apis.addressorsort.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
},
});
return data;
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
class: 'sortable-tree-demo',
}),
);
function handleEdit(record?: any) {
editModalApi.setData({
isUpdate: Boolean(record && record.guid),
record: JSON.parse(JSON.stringify(record || {})),
});
editModalApi.open();
}
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: '是否确认删除该条记录?',
okType: 'danger',
onOk: async () => {
await Apis.addressorsort.post_deletes({ params: { ids: row.guid } });
message.success('删除成功');
triggerProxy('reload');
},
});
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
});
message.success('导出成功');
}
}
const rowDrop = () => {
const $grid = xGridRef.value;
sortable2 = Sortable.create(
$grid!.$el.querySelector(
'.body--wrapper>.vxe-table--body tbody',
) as HTMLElement,
{
handle: '.drag-btn',
onEnd: async (sortableEvent) => {
const newIndex = sortableEvent.newIndex as number;
const oldIndex = sortableEvent.oldIndex as number;
const res = xGridRef.value?.getTableData();
const tableData = res?.fullData || [];
const currRow = tableData.splice(oldIndex, 1)[0];
tableData.splice(newIndex, 0, currRow);
//
const hideLoading = message.loading('提交中', 0);
try {
const data = JSON.parse(JSON.stringify(tableData));
// const data = tableData.map((item, index) => {
// return {
// ...item,
// sort: index + 1,
// };
// });
data.forEach((item, index) => {
item.sort = index + 1;
});
await Apis.addressorsort.post_saveBatch({ data });
triggerProxy('reload');
} catch (error) {
console.error(error);
} finally {
hideLoading();
}
},
},
);
};
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
xGridRef.value?.setRadioRow(row);
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
let initTime: any;
nextTick(() => {
//
initTime = setTimeout(() => {
rowDrop();
}, 500);
});
onMounted(() => {
triggerProxy('reload');
});
onUnmounted(() => {
clearTimeout(initTime);
if (sortable2) {
sortable2.destroy();
}
});
</script>
<template>
<Page content-class="h-full flex flex-col">
<EditModal
class="w-[600px] max-w-[80vw]"
@success="triggerProxy('reload')"
/>
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<!-- <vben-button variant="primary" @click="handleEdit()">
<MdiAdd class="mr-0.5 text-lg" />
新增
</vben-button>-->
<vben-button
:disabled="!selectRow || !selectRow.guid"
variant="warning"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
编辑
</vben-button>
<!-- <vben-button
:disabled="!selectRow || !selectRow.guid"
variant="destructive"
@click="handleDelete(selectRow)"
>
<MdiDelete class="mr-0.5 text-lg" />
删除
</vben-button> -->
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
<template #dragBtn>
<span class="drag-btn">
<span class="icon-[mdi--drag-variant]"></span>
<span class="text-xs text-gray-600">可拖动</span>
</span>
</template>
<template #dragTip>
<vxe-tooltip
v-model="showHelpTip"
content="按住后可以上下拖动排序"
enterable
>
<i
class="vxe-icon-question-circle-fill"
@click="showHelpTip = !showHelpTip"
></i>
</vxe-tooltip>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style scoped>
.sortable-tree-demo .drag-btn {
font-size: 12px;
text-align: center;
cursor: move;
}
.sortable-tree-demo .vxe-body--row.sortable-ghost,
.sortable-tree-demo .vxe-body--row.sortable-chosen {
background-color: #dfecfb;
}
</style>

View File

@ -0,0 +1,21 @@
import type { VxeGridPropTypes } from 'vxe-table';
export function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
return [
{
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
// { width: 80, title: '', slots: { default: 'dragBtn', header: 'dragTip' } },
{ field: 'sort', title: '发言顺序', width: 80 },
{ field: 'name', title: '单位/人员名称', width: 150 },
{ field: 'id', title: '单位/人员编号', width: 150 },
{ field: 'remarks', title: '备注', minWidth: 150 },
{ field: 'updateTime', title: '更新时间', minWidth: 150 },
{ field: 'creator', title: '创建人员', width: 120 },
{ field: 'createTime', title: '创建时间', minWidth: 150 },
];
}

View File

@ -0,0 +1,83 @@
<script setup lang="ts">
import { ref } from 'vue';
import { Page } from '@vben/common-ui';
import AddressorSortSetting from './components/addressor-sort-setting/addressor-sort-setting.vue';
// import AutoPeople from "./components/auto-people/AutoPeople.vue";
/** 异步加载的组件,用到的时候再加载组件 */
// -- 1
// const AddressorSortSetting = defineAsyncComponent(() => {
// return import(
// './components/addressor-sort-setting/addressor-sort-setting.vue'
// );
// });
const tabs = ref([
{
title: '发言人配置',
desc: '配置各单位发言人顺序',
key: 1,
},
]);
const tabInfo = ref(tabs.value[0]);
/**
* 切换事件
*/
function handleTabChange(item) {
tabInfo.value = item;
}
</script>
<template>
<Page content-class="h-full">
<a-row class="h-full">
<a-col :span="5" class="min-w-[200px]">
<a-list :data-source="tabs" item-layout="horizontal" size="small">
<template #renderItem="{ item }">
<a-list-item
:class="{ active: tabInfo.key === item.key }"
class="list-item cursor-pointer"
@click="handleTabChange(item)"
>
<a-list-item-meta>
<template #title>
<span> {{ item.title }}</span>
</template>
<template #description>
<span> {{ item.desc }}</span>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</a-col>
<a-col :span="19" class="flex min-w-[700px] flex-col">
<AddressorSortSetting v-if="tabInfo.key === 1" />
</a-col>
</a-row>
</Page>
</template>
<style lang="scss" scoped>
.active {
color: #2d8cf0;
background: #f0faff;
:deep(.ant-list-item-meta-title) {
color: #2d8cf0 !important;
}
:deep(.ant-list-item-meta-description) {
color: #2d8cf0 !important;
}
&:hover {
background: #f0faff;
}
}
</style>

View File

@ -189,7 +189,7 @@ const form2Binding = ref({
function getColumns(): VxeGridPropTypes.Columns {
return [
{ width: 80, title: '', slots: { default: 'dragBtn', header: 'dragTip' } },
// { width: 80, title: '', slots: { default: 'dragBtn', header: 'dragTip' } },
{ type: 'seq', title: '发言顺序', width: 80 },
{ field: 'addressor', title: '发言人员', width: 150 },
{

View File

@ -538,6 +538,9 @@ export default {
/** 合同系统/选商废除 退回 */
post_abolishRollback: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/abolishRollback', data),
/** 合同系统/选商 流程启动(非待办提交) */
post_flowStart: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/flowStart', data),
},
lvxChange: {
/** 合同系统/履行/履行提示/合同变更 保存合同变更申请 */
@ -613,7 +616,7 @@ export default {
/** 合同系统/归档/合同归档 保存合同归档 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractFilingFormal/save', data),
/** 合同系统/归档/合同回档 分页查询 */
/** 合同系统/归档/合同回档 分页查询-已归档 */
get_pageArchivedContract: (data?: QueryOptions) =>
http.get('/app/contractFilingFormal/pageArchivedContract', data),
/** 合同系统/归档/合同回档 回档 */
@ -828,5 +831,19 @@ export default {
/** 合同系统/签约授权 签约授权提交 */
post_flowStart: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/flowStart', data),
/** 合同系统/签约授权 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/deletes', data),
},
addressorsort: {
/** 协同办公/会议管理/发言人顺序配置 发言人顺序查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/addressorsort/page', data),
/** 协同办公/会议管理/发言人顺序配置 发言人排序保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/addressorsort/save', data),
/** 协同办公/会议管理/发言人顺序配置 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/addressorsort/deletes', data),
},
};