合同相关完善

This commit is contained in:
z9130 2024-09-28 19:47:43 +08:00
parent 736de72e9d
commit 68432d4d68
32 changed files with 1015 additions and 1237 deletions

View File

@ -33,7 +33,7 @@ const tokenTheme = computed(() => {
const dictStore = useDictStore();
if (dictStore.initDict) {
// dictStore.setDictMap();
dictStore.setDictMap();
}
</script>
@ -64,4 +64,52 @@ if (dictStore.initDict) {
.ant-btn__warning {
@apply bg-warning text-warning-foreground hover:bg-warning/90 shadow;
}
.ant-checkbox-disabled .ant-checkbox-inner {
background: #fafafa;
color: #333;
}
.ant-input-number-disabled {
background: #fafafa;
color: #333;
}
.ant-input-affix-wrapper-disabled,
.ant-input-affix-wrapper[disabled] {
background: #fafafa;
color: #333;
}
.ant-radio-wrapper-disabled {
background: #fafafa;
color: #333;
}
.ant-radio-wrapper .ant-radio-disabled .ant-radio-inner {
background-color: rgba(50, 54, 57, 0.04);
border-color: hsl(240 5.9% 90%);
}
.ant-picker.ant-picker-disabled {
background: #fafafa;
color: #333;
}
.ant-select-disabled.ant-select:not(.ant-select-customize-input)
.ant-select-selector {
background: #fafafa;
color: #333;
}
.ant-picker .ant-picker-input > input-disabled,
.ant-picker .ant-picker-input > input[disabled] {
background: #fafafa;
color: #333 !important;
}
.ant-input-disabled,
.ant-input[disabled] {
background: #fafafa;
color: #333;
}
</style>

View File

@ -0,0 +1,55 @@
<script lang="ts" setup>
import { nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { logger } from 'common-utils';
const emit = defineEmits<{
(e: 'confirm', data: any): void;
}>();
const isConfirmLoading = ref(false);
const data = ref({
title: '',
schema: {},
});
const formRef = ref();
const formBinding = ref();
const [Modal, modalApi] = useVbenModal({
async onOpenChange(isOpen: boolean) {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>() || {};
formBinding.value = data.value.schema || {};
nextTick(() => {});
}
isConfirmLoading.value = false;
},
async onConfirm() {
isConfirmLoading.value = true;
try {
await formRef.value?.submit();
emit('confirm', formRef.value.form);
} catch (error) {
logger.error('', error);
} finally {
isConfirmLoading.value = false;
}
},
});
</script>
<template>
<Modal
:confirm-loading="isConfirmLoading"
:loading="isConfirmLoading"
:title="data.title"
>
<fs-form v-if="formBinding.columns" ref="formRef" v-bind="formBinding" />
</Modal>
</template>

View File

@ -106,14 +106,12 @@ function handleMakeAll() {
}
function handleViewAll() {
console.log('viewAll');
router.push('/user/todo');
}
const isDev = import.meta.env.MODE === 'development';
const value = ref(localStorage.getItem('@@@proxy_type') || ''); // /zp
function handleMenuClick(e) {
console.log(e);
if (e.key === 'pro') {
localStorage.setItem('@@@proxy_type', '');
} else {

View File

@ -37,6 +37,7 @@ const routes: RouteRecordRaw[] = [
name: 'ContractApprovalEdit',
path: '/contract/approval/edit/:id?',
beforeEnter: (e) => {
console.log('e', e);
if (e.params.id && e.params.id === ':id') {
e.params.id = '';
e.fullPath = '/contract/approval/edit';

View File

@ -38,6 +38,9 @@ export const useDictStore = defineStore('app-dict', () => {
*/
const setDictMap = async (): Promise<boolean> => {
try {
// 模拟网络请求
// await new Promise((resolve) => setTimeout(resolve, 2000));
const data = await Apis.dictData.get_page({
params: { pageNum: 1, pageSize: 10_000 },
});

View File

@ -1,4 +1,6 @@
/** 数据字典工具类 */
import { computed } from 'vue';
import Apis from '#/api';
import { useDictStore } from '#/store/dict';
import dataModule from '#/utils/dict/static.data';
@ -7,6 +9,10 @@ export * from './shared';
const dictStore = useDictStore();
const dictData = computed(() => {
return dictStore.dictMap;
});
/**
* dictType
*
@ -29,7 +35,7 @@ export interface DictDataOptions {
}
export function getDictDatas(dictType: string) {
return dictStore.getDictMap[dictType] || [];
return dictData.value[dictType] || [];
}
export function getDictOpts(dictType: string) {
@ -58,7 +64,7 @@ export async function getDictDatasAsync(dictTypes: string[]) {
dictDataMap[dictType].push({
...dictData,
value: dictData.value,
label: dictData.name,
label: dictData.label,
colorType: dictData.colorType,
cssClass: dictData.cssClass,
} as DictDataType);
@ -100,7 +106,7 @@ export function getDictOptions(
const dictOption: DictDataType[] = [];
valueType ||= 'string';
const dictOptions: DictDataType[] = getDictDatas(dictType);
const dictOptions: DictDataType[] = dictData.value[dictType] || [];
if (dictOptions && dictOptions.length > 0) {
dictOptions.forEach((dict: DictDataType) => {
dictOption.push({
@ -166,6 +172,42 @@ export function getDictObj(dictType: string, value: any): DictDataType | null {
}
}
/** 获取指定 value 的字典数据 */
export function getDictObjByOptions(
options: DictDataType[],
value: any,
): DictDataType | null {
if (options) {
if (value) {
const result = options.find((dict: DictDataType) => dict.value === value);
return result || null;
}
return null;
} else {
return null;
}
}
/** 获取指定 value 的字典数据 */
export async function getDictObjAsync(
dictType: string,
value: any,
): Promise<DictDataType | null> {
const dictOptions = await getDictOptionsAsync(dictType);
if (dictOptions) {
if (value) {
return (
dictOptions.find(
(dict: DictDataType) => dict.value === value.toString(),
) || null
);
}
return null;
} else {
return null;
}
}
/** 获取字典默认数据 */
export function getDictDefaultObj(dictType: string): DictDataType | null {
const dictOptions: DictDataType[] = getDictDatas(dictType);

View File

@ -1,20 +1,7 @@
import { dict } from '@fast-crud/fast-crud';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
/**
*
*
*/
function filterContractTypes(contractTypeData: any = [], parentId: string) {
return contractTypeData
.map((item) => {
item.label = item.contrLevelName;
item.value = item.contrLevelId;
return item;
})
.filter((item) => item.parentId === parentId);
}
import { filterContractTypes } from '#/views/contract/utils';
export function getFormSchema(params: any = {}) {
const { contractTypeData, readOnly = false } = params;
@ -28,16 +15,9 @@ export function getFormSchema(params: any = {}) {
name: 'a-input',
vModel: 'value',
allowClear: false,
disabled: readOnly,
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return <span>{form.contractName}</span>;
},
},
rules: [{ required: true }],
rules: [{ required: true, message: '请输入合同名称' }],
},
ctrType: {
title: '合同类别',
@ -53,6 +33,7 @@ export function getFormSchema(params: any = {}) {
return filterContractTypes(contractTypeData, '-1');
},
}),
disabled: readOnly,
},
valueChange: {
immediate: true, // 是否立即执行一次
@ -62,21 +43,7 @@ export function getFormSchema(params: any = {}) {
getComponentRef('ctrTwoType').reloadDict(); // 执行city的select组件的reloadDict()方法触发“city”重新加载字典
},
},
conditionalRender: {
match({ form }) {
return readOnly;
},
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>;
},
},
rules: [{ required: true }],
rules: [{ required: true, message: '请选择合同类别' }],
},
ctrTwoType: {
title: '二级类别',
@ -89,25 +56,13 @@ export function getFormSchema(params: any = {}) {
prototype: true,
dict: dict({
async getData({ form = {} }) {
console.log(form);
return filterContractTypes(contractTypeData, form.ctrType);
},
}),
disabled: readOnly,
},
conditionalRender: {
match({ form }) {
return readOnly;
},
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>;
},
},
rules: [{ required: true }],
rules: [{ required: true, message: '请选择二级类别' }],
},
frameProtocol: {
title: '框架协议',
@ -119,19 +74,9 @@ export function getFormSchema(params: any = {}) {
dict: dict({
data: getDictOptions(DICT_TYPE.common_whether),
}),
disabled: readOnly,
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{getDictObj(DICT_TYPE.common_whether, form.frameProtocol)?.label}
</span>
);
},
},
rules: [{ required: true, message: '请选择框架协议' }],
},
frameProtocolCtr: {
title: '框架协议下的合同',
@ -144,22 +89,9 @@ export function getFormSchema(params: any = {}) {
dict: dict({
data: getDictOptions(DICT_TYPE.common_whether),
}),
disabled: readOnly,
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{
getDictObj(DICT_TYPE.common_whether, form.frameProtocolCtr)
?.label
}
</span>
);
},
},
rules: [{ required: true, message: '请选择框架协议下的合同' }],
},
fundAllocation: {
title: '资金流向',
@ -173,6 +105,7 @@ export function getFormSchema(params: any = {}) {
dict: dict({
data: getDictOptions(DICT_TYPE.contract_fund_flow),
}),
disabled: readOnly,
},
valueChange: {
immediate: true, // 是否立即执行一次
@ -183,21 +116,6 @@ export function getFormSchema(params: any = {}) {
)?.label;
},
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{
getDictObj(DICT_TYPE.contract_fund_flow, form.fundAllocation)
?.label
}
</span>
);
},
},
rules: [{ required: true, message: '请选择资金流向' }],
},
fundDitch: {
@ -212,21 +130,7 @@ export function getFormSchema(params: any = {}) {
dict: dict({
data: getDictOptions(DICT_TYPE.contract_funding_source),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{
getDictObj(DICT_TYPE.contract_funding_source, form.fundDitch)
?.label
}
</span>
);
},
disabled: readOnly,
},
rules: [{ required: true, message: '请选择资金渠道' }],
},
@ -241,14 +145,7 @@ export function getFormSchema(params: any = {}) {
class: 'w-full',
min: 0,
max: 9999,
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return <span class="">{form.budgetSum}</span>;
},
disabled: readOnly,
},
},
priceType: {
@ -263,23 +160,7 @@ export function getFormSchema(params: any = {}) {
dict: dict({
data: getDictOptions(DICT_TYPE.contract_currency_unit),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="mr-2">
{
getDictObj(
DICT_TYPE.contract_currency_unit,
form.priceType || '',
)?.label
}
</span>
);
},
disabled: readOnly,
},
},
organiza: {
@ -290,25 +171,11 @@ 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),
data: getDictOptions(DICT_TYPE.contract_organization_form, 'number'),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{
getDictObj(DICT_TYPE.contract_organization_form, form.organiza)
?.label
}
</span>
);
},
disabled: readOnly,
},
rules: [{ required: true, message: '请选择组织形式' }],
},

View File

@ -10,6 +10,7 @@ import { message, Modal, type UploadChangeParam } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import temporaryFormModal from '#/components/temporary-form-modal/temporary-form-modal.vue';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
@ -29,6 +30,10 @@ const [ChooseSigningBasisModal, chooseSigningBasisModalApi] = useVbenModal({
connectedComponent: chooseSigningBasisModal,
});
const [TemporaryFormModal, temporaryFormModalApi] = useVbenModal({
connectedComponent: temporaryFormModal,
});
const userStore = useUserStore();
const userInfo = computed(() => userStore.userInfo);
@ -38,9 +43,10 @@ const fileUploader = new FileUploader({});
const router = useRouter();
const route = useRoute();
const id = ref(route.params.id);
const auditId = ref();
const pageRef = ref();
const currData = ref<any>(null);
const currData = ref<any>({});
const formRef = ref();
@ -211,9 +217,23 @@ async function handleSave() {
try {
await formRef.value.submit();
} catch {
message.error('请完成必填项的填写');
return;
}
try {
let newForm: any = {};
//
const tableFullData = xGridRef.value?.getTableData().fullData;
if (tableFullData && tableFullData.length > 0) {
newForm.basisId = tableFullData[0].basisId;
} else {
message.error('请选择签约依据');
return;
}
//
const fileList = formRef.value.form.fileList;
let files: any = [];
@ -257,18 +277,10 @@ async function handleSave() {
let result: any = {};
//
const tableFullData = xGridRef.value?.getTableData().fullData;
if (tableFullData && tableFullData.length > 0) {
newForm.basisId = tableFullData[0].basisId;
} else {
message.error('请选择签约依据');
return;
}
result = await Apis.contractBaseInfo.post_apply({ data: newForm });
id.value = result.value;
auditId.value = result.value;
message.success('保存成功');
Modal.confirm({
@ -297,6 +309,93 @@ async function handleSubmit() {
chooseUserModalApi.open();
}
async function handleAudit(
type: 'accessConfirm' | 'reject' | 'rejectConfirm',
data: any,
) {
console.log(type);
if (type === 'accessConfirm') {
Modal.confirm({
title: '提示',
content: '是否确认审核通过?',
onOk: async () => {
try {
await Apis.contractBaseInfo.post_submit({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId: currData.value.taskId,
nodeId: '',
comment: '通过',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
}
},
});
}
if (type === 'reject') {
Modal.confirm({
title: '提示',
content: '是否确认退回?',
onOk: () => {
temporaryFormModalApi.setData({
title: '退回原因',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
},
},
});
temporaryFormModalApi.open();
},
});
}
if (type === 'rejectConfirm') {
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_rollback({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId: currData.value.taskId,
nodeId: '',
comment,
},
});
temporaryFormModalApi.close();
message.success('退回成功');
back();
} catch (error) {
logger.error('合同立项退回失败', error);
message.error('退回失败,请稍候再试');
}
}
}
onMounted(async () => {
isLoading.value = true;
@ -311,7 +410,8 @@ onMounted(async () => {
params: { guid: id.value },
});
currData.value = data;
auditId.value = id.value;
currData.value = data || {};
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
@ -325,6 +425,7 @@ onMounted(async () => {
);
nextTick(() => {
console.log(formRef.value);
formRef.value.setFormData(data);
});
@ -380,6 +481,11 @@ onMounted(async () => {
<ChooseSigningBasisModal class="w-[950px]" @confirm="handleChooseConfirm" />
<TemporaryFormModal
class="w-[950px]"
@confirm="handleAudit('rejectConfirm', $event)"
/>
<a-affix
:offset-top="0"
:style="{ zIndex: 50 }"
@ -395,16 +501,37 @@ onMounted(async () => {
保存
</vben-button>
<vben-button
v-if="!id || currData.step === 'edit' || !currData.taskId"
v-if="!id || ['edit'].includes(currData.step) || !currData.taskId"
:disabled="!auditId"
variant="primary"
@click="handleSubmit()"
>
提交
</vben-button>
<vben-button
v-if="
['departmentAudit'].includes(currData.step) && currData.taskId
"
:disabled="!auditId"
variant="primary"
@click="handleAudit('accessConfirm')"
>
通过
</vben-button>
<vben-button
v-if="
['departmentAudit'].includes(currData.step) && currData.taskId
"
:disabled="!auditId"
variant="destructive"
@click="handleAudit('reject')"
>
退回
</vben-button>
<vben-button
v-if="
id &&
currData.step !== 'edit' &&
!['edit', 'departmentAudit'].includes(currData.step) &&
currData.inputUserId === userInfo!.userId
"
variant="destructive"

View File

@ -2,35 +2,13 @@ import type { VxeGridPropTypes } from 'vxe-table';
import { dict } from '@fast-crud/fast-crud';
import Apis from '#/api';
import { useRender } from '#/hooks/useRender';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { getContractTypes } from '#/views/contract/utils';
export const PrimaryKey = 'guid';
/**
*
*
*/
async function filterContractTypes(parentId: string) {
try {
const contractReferTypeData = await Apis.contractReferType.get_list({
params: {},
});
return contractReferTypeData.rows
.map((item) => {
item.label = item.contrLevelName;
item.value = item.contrLevelId;
return item;
})
.filter((item) => item.parentId === parentId);
} catch (error) {
console.log(error);
return [];
}
}
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
export function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
return [
{
type: 'radio',
@ -216,8 +194,8 @@ export function getFormSchema(_params: any = {}) {
vModel: 'value',
class: 'min-w-[200px]',
dict: dict({
async getData({ form = {} }) {
return await filterContractTypes('-1');
async getData(_context) {
return await getContractTypes('-1');
},
}),
},

View File

@ -1,20 +1,7 @@
import { dict } from '@fast-crud/fast-crud';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
/**
*
*
*/
function filterContractTypes(contractTypeData: any = [], parentId: string) {
return contractTypeData
.map((item) => {
item.label = item.contrLevelName;
item.value = item.contrLevelId;
return item;
})
.filter((item) => item.parentId === parentId);
}
import { filterContractTypes } from '#/views/contract/utils';
export function getFormSchema(params: any = {}) {
const { contractTypeData } = params;
@ -81,10 +68,7 @@ export function getFormSchema(params: any = {}) {
class: 'min-w-[200px]',
dict: dict({
async getData({ form = {} }) {
if (form.ctrType) {
return filterContractTypes(contractTypeData, form.ctrType);
}
return contractTypeData;
return filterContractTypes(contractTypeData, form.ctrType);
},
}),
},

View File

@ -32,7 +32,7 @@ const gridOptions = reactive(
autoLoad: false,
ajax: {
query: async ({ page }) => {
const data = await Apis.contractBaseInfo.get_page({
const data = await Apis.selectMerchantsBasicInfo.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,

View File

@ -37,6 +37,7 @@ const data = ref({
});
const checkRecords = ref([]);
const limitMultipleNum = ref(1);
const searchBinding = ref({
...getFormSchema(),
@ -70,7 +71,7 @@ const gridOptions = reactive(
},
},
rowConfig: {
keyField: 'providerId',
keyField: 'guid',
},
checkboxConfig: {
labelField: 'providerId',
@ -84,7 +85,7 @@ const gridOptions = reactive(
const checkRecordIds =
checkRecords.value.map((item) => item.guid) || [];
if (
checkRecords.value.length === 0 ||
checkRecords.value.length < limitMultipleNum.value ||
checkRecordIds.includes(row.guid)
) {
return true;
@ -123,8 +124,8 @@ function handleCheckboxChange(e) {
}
console.log('[ checkRecords.value ] >', checkRecords.value);
if (allRows.length > 0) {
messageApi.warning('最多只能选择1条数据');
if (allRows.length >= limitMultipleNum.value) {
messageApi.warning(`最多只能选择${limitMultipleNum.value}条数据`);
}
}
@ -145,7 +146,10 @@ const [BaseModal, baseModalApi] = useVbenModal({
if (data.value.title) {
title.value = data.value.title;
}
console.log(data.value.userIds);
if (data.value.limitMultipleNum) {
limitMultipleNum.value = data.value.limitMultipleNum;
}
console.log(data.value.guids);
const rows: any = [];
for (const element of checkRecords.value) {
if (data.value.guids.includes(element.guid)) {
@ -195,7 +199,11 @@ const [BaseModal, baseModalApi] = useVbenModal({
v-bind="gridOptions"
@cell-click="handleCellClick"
@checkbox-change="handleCheckboxChange"
/>
>
<template #provider-name-slot="{ row }">
<span class=""> {{ row.providerName }}</span>
</template>
</VxeGrid>
</div>
</div>
</BaseModal>

View File

@ -1,12 +1,13 @@
<script setup lang="ts">
import { onMounted, reactive } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getTodoColumns } from '#/views/contract/schema';
import { toDetailPage } from '#/views/contract/utils';
import { toDetail, toDetailPage } from '#/views/contract/utils';
const props = withDefaults(
defineProps<{
@ -17,6 +18,8 @@ const props = withDefaults(
},
);
const router = useRouter();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef: xGrid2Ref, triggerProxy: triggerProxy2 } = useVxeTable({
@ -96,7 +99,7 @@ onMounted(() => {});
<template #title_slot="{ row }">
<span
class="cursor-pointer text-blue-500 hover:underline"
@click="toDetail(row)"
@click="toDetail(row.module, row.businessId, row)"
>
{{ row.contractName }}
</span>

View File

@ -1,8 +1,32 @@
import { dict } from '@fast-crud/fast-crud';
import { message } from 'ant-design-vue';
import dayjs, { type Dayjs } from 'dayjs';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
export function getFormSchema(_params: any = {}) {
export function getFormSchema(params: any = {}) {
const { chooseCompanyModalApi, formRef } = params || {};
const disabledDate = (current: Dayjs) => {
const form = formRef.value.form;
return current && current < dayjs(form.performStartDate);
};
const handleUpdateFormattedValue = () => {
const { performStartDate, performEndDate } = formRef.value.form;
if (
performStartDate &&
performEndDate &&
performEndDate < performStartDate
) {
message.error('截止时间不能早于开始时间');
formRef.value.setFormData({
performEndDate: '',
});
}
};
return {
col: { span: 24 },
labelCol: { style: { width: '120px' } },
@ -78,46 +102,51 @@ export function getFormSchema(_params: any = {}) {
readOnly: true,
},
},
projectNum5: {
providerName: {
title: '合同相对人',
key: 'projectNum5',
col: { span: 16 },
key: 'providerName',
col: { span: 12 },
component: {
name: 'fs-dict-radio',
name: 'a-input',
vModel: 'value',
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_project_type),
}),
readOnly: true,
placeholder: '请选择合同相对人',
onClick: () => {
console.log(formRef.value.form);
chooseCompanyModalApi.setData({
title: '选择合同相对人',
guids: [formRef.value.form.providerId],
});
chooseCompanyModalApi.open();
},
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return <a-button type="primary"></a-button>;
},
rules: [{ required: true, message: '请选择合同相对人' }],
},
media: {
title: '公告发布方式',
key: 'media',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
},
},
isBid: {
title: '划分标段',
key: 'isBid',
isPerformDate: {
title: '履行期限',
key: 'isPerformDate',
col: { span: 24 },
// component: {
// name: "fs-dict-radio",
// vModel: "value",
// dict: dict({
// data: getDictOptions(DICT_TYPE.section_type)
// }),
// },
component: {
name: 'a-input',
vModel: 'value',
},
conditionalRender: {
match({ form }) {
match(_context) {
return true;
},
render({ form }) {
// 注意此处的v-model写法
const options1 = getDictOptions(
DICT_TYPE.deadlineForPerformance,
DICT_TYPE.contract_authorization_period,
'string',
);
@ -126,13 +155,41 @@ export function getFormSchema(_params: any = {}) {
<a-form-item class="!mb-0 inline-block">
<a-radio-group
options={options1}
v-model:value={form.isBid}
v-model:value={form.isPerformDate}
/>
</a-form-item>
<div class="w-2"></div>
{form.isBid === 1 && (
<a-form-item class="!mb-0 inline-block" label="相关约定">
<a-input v-model:value={form.xxxx} />
{form.isPerformDate === '0' && (
<div class="flex items-center">
<span class="mx-1"></span>
<a-form-item class="!mb-0 inline-block">
<a-date-picker
format="YYYY-MM-DD"
onChange={handleUpdateFormattedValue}
placeholder=""
v-model:value={form.performStartDate}
value-format="YYYY-MM-DD"
/>
</a-form-item>
<span class="mx-1"></span>
<a-form-item class="!mb-0 inline-block">
<a-date-picker
disabledDate={disabledDate}
format="YYYY-MM-DD"
onChange={handleUpdateFormattedValue}
placeholder=""
v-model:value={form.performEndDate}
value-format="YYYY-MM-DD"
/>
</a-form-item>
</div>
)}
{form.isPerformDate === '1' && (
<a-form-item
class="!mb-0 inline-block flex-1"
label=" 相关约定"
>
<a-input v-model:value={form.performDescribe} />
</a-form-item>
)}
</div>
@ -140,18 +197,18 @@ export function getFormSchema(_params: any = {}) {
},
},
},
projectNum7: {
performPlace: {
title: '履行地点',
key: 'projectNum7',
key: 'performPlace',
col: { span: 16 },
component: {
name: 'a-input',
vModel: 'value',
},
},
projectNum8: {
theIndexNum: {
title: '专项号',
key: 'projectNum8',
key: 'theIndexNum',
col: { span: 8 },
component: {
name: 'a-input',
@ -170,33 +227,31 @@ export function getFormSchema(_params: any = {}) {
}),
},
},
projectNum10: {
warranty: {
title: '质保金期限',
key: 'projectNum10',
key: 'warranty',
col: { span: 8 },
component: {
name: 'a-input-number',
vModel: 'value',
},
suffixRender({ value }) {
return <span class="mr-2"></span>;
min: 0,
addonAfter: '个月',
},
},
projectNum11: {
subsistRatio: {
title: '预付款比例',
key: 'projectNum11',
key: 'subsistRatio',
col: { span: 16 },
component: {
name: 'a-input-number',
vModel: 'value',
},
suffixRender({ value }) {
return <span class="mr-2">%</span>;
min: 0,
addonAfter: '%',
},
},
stockPlanMx: {
inputOpinion: {
title: '承办人意见',
key: 'stockPlanMx',
key: 'inputOpinion',
col: { span: 24 },
labelWrap: true,
component: {

View File

@ -2,38 +2,43 @@
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { Page, useVbenModal } from '@vben/common-ui';
import { MdiUpload } from '@vben/icons';
import { useUserStore } from '@vben/stores';
import {
message,
Modal,
type UploadChangeParam,
type UploadFile,
type UploadProps,
} from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
import chooseCompanyModal from '../../company/list/choose-company-modal.vue';
import { getFormSchema as getFormSchemaByBaseInfo } from './basic-info-curd';
import { getFormSchema } from './curd';
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: 'xGridRef' });
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
connectedComponent: chooseUserModal,
});
const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
const fileUploader = new FileUploader({});
const router = useRouter();
const route = useRoute();
const id = route.params.id;
const id = ref(route.params.id);
const pageRef = ref();
const showHelpTip = ref(false);
const containerRef = ref();
const formRef = ref();
const formRefByBaseInfo = ref();
@ -49,7 +54,7 @@ const formBindingByBaseInfo = ref({
});
const formBinding = ref({
...getFormSchema(),
...getFormSchema({ chooseCompanyModalApi, formRef }),
});
function getColumns(): any {
@ -86,9 +91,8 @@ const gridOptions = reactive(
);
const fileList = ref<UploadFile[]>([]);
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
return false;
};
const fileListByProfile = ref<UploadFile[]>([]);
function handleBack() {
Modal.confirm({
@ -111,6 +115,10 @@ const handleChange = (info: UploadChangeParam) => {
fileList.value = info.fileList.length > 0 ? info.fileList : [];
};
const handleChangeByProfile = (info: UploadChangeParam) => {
fileListByProfile.value = info.fileList.length > 0 ? info.fileList : [];
};
function handleDelete() {
Modal.confirm({
title: '提示',
@ -143,6 +151,23 @@ function handleFold() {
function loadDataByContractTypeData() {}
async function handleChooseCompanyConfirm(e) {
chooseCompanyModalApi.close();
formRef.value.setFormData({
providerId: e[0].guid,
providerName: e[0].providerName,
});
}
async function handleChooseUserConfirm(e) {
chooseUserModalApi.close();
formRef.value.setFormData({
assigneeList: e.map((item) => item.ACCOUNT_ID),
});
// isLoading.value = true;
}
function handleDownloadTemplate() {}
async function handleSave() {
isLoading.value = true;
@ -151,85 +176,41 @@ async function handleSave() {
console.log(formRef.value);
await formRef.value.submit();
await formRefByBaseInfo.value.submit();
const contractForm = formRefByBaseInfo.value.form;
const bussinessForm = formRef.value.form;
bussinessForm.priceStyleName = getDictObj(
DICT_TYPE.contract_price_style,
bussinessForm.priceStyleId,
)?.label;
bussinessForm.choiceTypeName = getDictObj(
DICT_TYPE.contract_selection_method,
bussinessForm.choiceType,
)?.label;
const form = formRef.value.form;
//
{
const tempFileList = contractForm.fileList;
let tempFiles: any = [];
if (fileList.value && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
console.log(tempFiles);
if (tempFiles) {
contractForm.fileUuid = (
tempFiles.map((item) => item.fileUuid) || []
).join(',');
}
}
// {
// const tempFileList = contractForm.fileList;
// let tempFiles: any = [];
// if (fileList.value && tempFileList.length > 0) {
// tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
// }
// console.log(tempFiles);
// if (tempFiles) {
// contractForm.fileUuid = (
// tempFiles.map((item) => item.fileUuid) || []
// ).join(',');
// }
// }
//
{
const tempFileList = fileList.value;
let tempFiles: any = [];
if (fileList.value && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
console.log(tempFiles);
if (tempFiles) {
bussinessForm.fileUuid = (
tempFiles.map((item) => item.fileUuid) || []
).join(',');
}
}
const form = {
contractBaseInfo: contractForm,
selectMerchantsBasicInfo: bussinessForm,
biddingList: xGridRef.value?.getTableData().fullData,
};
if (form.selectMerchantsBasicInfo.isBid) {
const biddingList: any[] = xGridRef.value?.getTableData().fullData || [];
let index = 1;
for (const item of biddingList) {
if (!item.phaseName) {
message.error(`标段信息中的标段名称不能为空`);
return;
}
if (!item.phaseMoney) {
message.error(`标段信息中的预算金额不能为空`);
return;
}
if (!item.phaseDesc) {
message.error(`标段信息中的标段范围说明不能为空`);
return;
}
item.phaseSeq = `${index}`;
index++;
}
form.biddingList = biddingList;
}
// {
// const tempFileList = fileList.value;
// let tempFiles: any = [];
// if (fileList.value && tempFileList.length > 0) {
// tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
// }
// if (tempFiles) {
// bussinessForm.fileUuid = (
// tempFiles.map((item) => item.fileUuid) || []
// ).join(',');
// }
// }
console.log('提交表单', form);
return;
const userStore = useUserStore();
let newForm = {};
// return;
//
// let fileList = formRef.value.form.fileList
@ -242,51 +223,22 @@ async function handleSave() {
// newForm.fileUuid = (files.map((item) => item.fileUuid) || []).join(',')
// }
newForm = Object.assign({}, formRef.value.form, newForm);
delete newForm.fileList;
// name
for (const item of contractTypeData.value) {
if (item.contrLevelId == newForm.ctrType) {
newForm.ctrTypeName = item.contrLevelName;
}
if (item.contrLevelId == newForm.ctrTwoType) {
newForm.ctrTwoTypeName = item.contrLevelName;
}
}
newForm.fundDitchName = getDictObj(
DICT_TYPE.contract_funding_source,
newForm.fundDitch,
)?.label;
newForm.priceTypeName = getDictObj(
DICT_TYPE.contract_currency_unit,
newForm.priceType,
)?.label;
newForm.contractMoney = newForm.budgetSum;
newForm.currentContStepId = 0;
console.log(newForm);
await Apis.contractBaseInfo.post_apply({ data: newForm }).then((data) => {
message.success('保存成功');
Modal.confirm({
title: '提示',
content: '保存成功!是否进行提交?',
onOk: () => {
handleSubmit();
},
onCancel: () => {
back();
},
});
const data = await Apis.sbCtrBasePt.post_save({ data: form });
id.value = data.value;
message.success('保存成功');
Modal.confirm({
title: '提示',
content: '保存成功!是否进行提交?',
onOk: () => {
handleSubmit();
},
onCancel: () => {
back();
},
});
} catch (error) {
message.error('提交失败,请稍候再试');
console.log(error);
logger.error('申报结果报错失败', error);
} finally {
isLoading.value = false;
}
@ -294,13 +246,12 @@ async function handleSave() {
async function handleSubmit() {
try {
await Apis.contractBaseInfo.post_apply({ data: {} }).then((data) => {
message.success('提交成功');
back();
});
await Apis.sbCtrBasePt.post_submit({ params: { guid: id.value } });
message.success('提交成功');
back();
} catch (error) {
message.error('提交失败,请稍候再试');
console.log(error);
logger.error('申报结果报错失败', error);
} finally {
isLoading.value = false;
}
@ -313,10 +264,8 @@ const currData = ref({});
onMounted(async () => {
isLoading.value = true;
console.log(id);
try {
if (id) {
if (id.value) {
const contractReferTypeData = await Apis.contractReferType.get_list({
params: {},
});
@ -328,7 +277,7 @@ onMounted(async () => {
//
const contract: any = await Apis.contractBaseInfo.get_getOne({
params: { contractId: id },
params: { contractId: id.value },
});
if (contract && contract.contractId) {
contractData.value = contract;
@ -356,7 +305,7 @@ onMounted(async () => {
throw new Error('当前合同信息不存在');
}
} catch (error) {
console.log(error);
logger.error('申报结果报错失败', error);
Modal.error({
title: '提示',
@ -373,6 +322,17 @@ onMounted(async () => {
<template>
<Page ref="pageRef" content-class="h-full flex flex-col">
<ChooseCompanyModal
class="w-[950px]"
multiple
@confirm="handleChooseCompanyConfirm"
/>
<ChooseUserModal
class="w-[950px]"
multiple
@confirm="handleChooseUserConfirm"
/>
<a-affix
:offset-top="0"
:style="{ zIndex: 50 }"
@ -425,9 +385,9 @@ onMounted(async () => {
<a-form-item label="附件上传" name="fileList">
<a-upload
v-model:file-list="fileList"
:before-upload="beforeUpload"
:before-upload="() => false"
:max-count="3"
accept=".pdf,.ppt,.pptx"
accept=".pdf,.ppt,.pptx,.doc,.docx,.xls,.xlsx,.zip,jpg,png,jpeg,bmp"
name="file"
@change="handleChange"
>
@ -449,12 +409,12 @@ onMounted(async () => {
<a-form :label-col="{ style: { width: '120px' } }">
<a-form-item label="附件上传" name="fileList">
<a-upload
v-model:file-list="fileList"
v-model:file-list="fileListByProfile"
:before-upload="() => false"
:max-count="3"
accept=".pdf,.ppt,.pptx"
accept=".doc,.docx"
name="file"
@change="handleChange"
@change="handleChangeByProfile"
>
<a-button>
<MdiUpload />

View File

@ -1,39 +1,28 @@
<script setup lang="ts">
import { ref, computed, reactive, onMounted } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import {
MdiAdd,
MdiUpdate,
MdiDelete,
MdiImport,
MdiExport,
MdiRadioUnchecked,
MdiRadioChecked,
} from '@vben/icons';
import { getFormSchema, getColumns, PrimaryKey } from './crud.tsx';
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 { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import {
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const checkedValue = ref('all');
const exportSearchParams = ref<any>({
daterange: getMonthStartAndEnd(),
});
const searchRef = ref();
let isConfirmLoading = ref(false);
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
@ -63,7 +52,7 @@ const gridOptions = reactive(
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push('/contract/declaration/edit/' + record['ctrBaseId']);
router.push(`/contract/declaration/edit/${record.ctrBaseId}`);
} else {
router.push('/contract/declaration/edit');
}
@ -111,31 +100,27 @@ const searchForm = ref({
</script>
<template>
<Page contentClass="h-full flex flex-col">
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchForm">
<template #search_price="{ row }">
<a-input-number v-model:value="row.budgetSum1" placeholder="">
</a-input-number>
<a-input-number v-model:value="row.budgetSum1" placeholder="" />
<span class="mx-1"></span>
<a-input-number v-model:value="row.budgetSum2" placeholder="">
</a-input-number>
<a-input-number v-model:value="row.budgetSum2" placeholder="" />
</template>
<template #form_time="{ row }">
<a-date-picker
v-model:value="row.startTime"
placeholder=""
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
>
</a-date-picker>
/>
<span class="mx-1"></span>
<a-date-picker
v-model:value="row.endTime"
placeholder=""
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
>
</a-date-picker>
/>
</template>
</fs-search>
@ -148,8 +133,8 @@ const searchForm = ref({
<template #toolbar_buttons>
<a-space>
<vben-button
variant="warning"
:disabled="!selectRow || !selectRow[PrimaryKey]"
variant="warning"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />

View File

@ -2,65 +2,23 @@
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { Page } from '@vben/common-ui';
import { MdiRadioChecked, MdiRadioUnchecked } from '@vben/icons';
import { message } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getMonthStartAndEnd } from '#/utils/time';
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const checkedValue = ref('all');
const exportSearchParams = ref<any>({
daterange: getMonthStartAndEnd(),
});
const searchRef = ref();
const isConfirmLoading = ref(false);
const [_Modal, modalApi] = useVbenModal({
async onConfirm() {
isConfirmLoading.value = true;
try {
let params = {};
if (checkedValue.value == 'daterange') {
params = {
startDate: exportSearchParams.value.daterange[0],
endDate: exportSearchParams.value.daterange[1],
};
}
const res = await Apis.zbgl
.post_export({
params,
config: {
meta: {
responseType: 'blob',
},
},
})
.send();
message.success('导出成功');
modalApi.close();
showExportModal.value = false;
} catch (error) {
console.error(error);
} finally {
isConfirmLoading.value = false;
}
console.info('onConfirm');
},
});
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
@ -131,20 +89,27 @@ onMounted(() => {
const searchForm = ref({
...getFormSchema(),
onSearch(context: any) {
onSearch(_context: any) {
triggerProxy('reload');
},
});
function toPage() {
window.open('/iframe/meeting/standing-book', '_blank');
}
function toDetail(row) {
window.open(`/iframe/meeting/start/${row.guid}`, '_blank');
}
function handlePrint(row, type: string) {}
async function handlePrint(row, type: string) {
const hideLoading = message.loading('加载中', 0);
try {
const form: any = {};
await Apis.qdSign.get_printApprove({
params: form,
});
} catch (error) {
logger.error('打印失败', error);
} finally {
hideLoading();
}
}
</script>
<template>
@ -187,6 +152,10 @@ function handlePrint(row, type: string) {}
>
签约确认
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
</a-space>
</template>

View File

@ -2,72 +2,27 @@
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { Page } from '@vben/common-ui';
import {
MdiAdd,
MdiDelete,
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message, Modal } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getMonthStartAndEnd } from '#/utils/time';
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const checkedValue = ref('all');
const exportSearchParams = ref<any>({
daterange: getMonthStartAndEnd(),
});
const searchRef = ref();
const isConfirmLoading = ref(false);
const [_Modal, modalApi] = useVbenModal({
async onConfirm() {
isConfirmLoading.value = true;
try {
let params = {};
if (checkedValue.value == 'daterange') {
params = {
startDate: exportSearchParams.value.daterange[0],
endDate: exportSearchParams.value.daterange[1],
};
}
const res = await Apis.zbgl
.post_export({
params,
config: {
meta: {
responseType: 'blob',
},
},
})
.send();
message.success('导出成功');
modalApi.close();
showExportModal.value = false;
} catch (error) {
console.error(error);
} finally {
isConfirmLoading.value = false;
}
console.info('onConfirm');
},
});
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
@ -76,7 +31,7 @@ const gridOptions = reactive(
autoLoad: false,
ajax: {
query: ({ page }) => {
return Apis.contractBaseInfo.get_page({
return Apis.personTask.get_pagePerformanceAudit({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
@ -98,29 +53,9 @@ const gridOptions = reactive(
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push(`/contract/perform/edit/${record[PrimaryKey]}`);
} else {
router.push('/contract/perform/edit');
}
}
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: '是否确认删除该条记录?',
okType: 'danger',
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({
params: { ids: row[PrimaryKey] },
});
message.success('删除成功');
triggerProxy('reload');
},
onCancel() {
console.log('Cancel');
},
});
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
@ -156,45 +91,15 @@ onMounted(() => {
const searchForm = ref({
...getFormSchema(),
onSearch(context: any) {
onSearch(_context: any) {
triggerProxy('reload');
},
});
function toPage() {
window.open('/iframe/meeting/standing-book', '_blank');
}
function toDetail(row) {
window.open(`/iframe/meeting/start/${row.guid}`, '_blank');
}
//
</script>
<template>
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchForm">
<template #search_price="{ row }">
<a-input-number v-model:value="row.budgetSum1" placeholder="" />
<span class="mx-1"></span>
<a-input-number v-model:value="row.budgetSum2" placeholder="" />
</template>
<template #form_time="{ row }">
<a-date-picker
v-model:value="row.startTime"
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
/>
<span class="mx-1"></span>
<a-date-picker
v-model:value="row.endTime"
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
/>
</template>
</fs-search>
<fs-search ref="searchRef" v-bind="searchForm" />
<div class="min-h-300px flex-1">
<vxe-grid
@ -204,10 +109,6 @@ function toDetail(row) {
>
<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[PrimaryKey]"
variant="warning"
@ -220,14 +121,6 @@ function toDetail(row) {
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow[PrimaryKey]"
variant="destructive"
@click="handleDelete(selectRow)"
>
<MdiDelete class="mr-0.5 text-lg" />
删除
</vben-button>
</a-space>
</template>

View File

@ -12,7 +12,7 @@ export const PrimaryKey = 'guid';
export function getTodoColumns(_params: any = {}): VxeGridPropTypes.Columns {
return [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{ field: 'contractId', title: '编号', width: 150 },
{
field: 'contractName',
title: '名称',

View File

@ -10,7 +10,7 @@ import { VxeGrid, type VxeGridPropTypes } from 'vxe-table';
import { unitComponentProps } from '#/common/unit';
import {
DICT_TYPE,
getDictObj,
getDictObjByOptions,
getDictOptions,
getDictOptionsAsync,
} from '#/utils/dict';
@ -66,6 +66,8 @@ export function getFormSchema(params?: any): any {
}
};
const dictMap: any = {};
return {
col: { span: 24 },
initialForm: {
@ -128,17 +130,17 @@ export function getFormSchema(params?: any): any {
allowClear: false,
dict: dict({
async getData(_context) {
return await getDictOptionsAsync(
DICT_TYPE.contract_authorization_type2,
);
const type = DICT_TYPE.contract_authorization_type2;
dictMap[type] = await getDictOptionsAsync(type);
return dictMap[type];
},
}),
},
valueChange: {
immediate: true, // 是否立即执行一次
handle({ form }) {
form.consignTypeName = getDictObj(
DICT_TYPE.contract_authorization_type,
async handle({ form }) {
form.consignTypeName = getDictObjByOptions(
dictMap[DICT_TYPE.contract_authorization_type2],
form.consignType,
)?.label;
},

View File

@ -1,320 +1,147 @@
import { dict } from '@fast-crud/fast-crud';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
/**
*
*
*/
function filterContractTypes(contractTypeData: any = [], parentId: string) {
return contractTypeData
.map((item) => {
item.label = item.contrLevelName;
item.value = item.contrLevelId;
return item;
})
.filter((item) => item.parentId === parentId);
}
import { DICT_TYPE, getDictOptionsAsync } from '#/utils/dict';
export function getFormSchema(params: any = {}) {
const { contractTypeData, readOnly = false } = params;
const { readOnly = false } = params;
return {
contractName: {
title: '合同名称',
key: 'contractName',
col: { span: 24 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return <span>{form.contractName}</span>;
},
},
rules: [{ required: true }],
col: { span: 24 },
labelCol: { style: { width: '120px' } },
initialForm: {
ourStampName: '克拉玛依市热力有限责任公司合同专用章',
},
ctrType: {
title: '合同类别',
key: 'ctrType',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
prototype: true,
dict: dict({
async getData(_context) {
return filterContractTypes(contractTypeData, '-1');
},
}),
},
valueChange: {
immediate: true, // 是否立即执行一次
handle({ form, value, getComponentRef }) {
form.ctrTwoType = undefined;
console.log(getComponentRef('ctrTwoType'));
getComponentRef('ctrTwoType').reloadDict(); // 执行city的select组件的reloadDict()方法触发“city”重新加载字典
columns: {
contractName: {
title: '合同名称',
key: 'contractName',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
disabled: readOnly,
},
},
conditionalRender: {
match({ form }) {
return readOnly;
},
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>;
contractNumber: {
title: '合同编号',
key: 'contractNumber',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
disabled: readOnly,
},
},
rules: [{ required: true }],
},
ctrTwoType: {
title: '二级类别',
key: 'ctrTwoType',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
prototype: true,
dict: dict({
async getData({ form = {} }) {
return filterContractTypes(contractTypeData, form.ctrType);
},
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
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>;
signUserName: {
title: '我方签约人',
key: 'signUserName',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
disabled: readOnly,
},
},
rules: [{ required: true }],
},
frameProtocol: {
title: '框架协议',
key: 'frameProtocol',
col: { span: 8 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.common_whether),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{getDictObj(DICT_TYPE.common_whether, form.frameProtocol)?.label}
</span>
);
signTime: {
title: '我方签字时间',
key: 'signTime',
col: { span: 12 },
component: {
name: 'a-date-picker',
vModel: 'value',
valueFormat: 'YYYY-MM-DD',
},
},
},
frameProtocolCtr: {
title: '框架协议下的合同',
key: 'frameProtocolCtr',
col: { span: 12 },
labelCol: { style: { width: '200px' } },
component: {
name: 'fs-dict-radio',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.common_whether),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{
getDictObj(DICT_TYPE.common_whether, form.frameProtocolCtr)
?.label
}
</span>
);
providerName: {
title: '合同相对人',
key: 'providerName',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
readOnly: true,
placeholder: '请选择合同相对人',
disabled: readOnly,
},
},
},
fundAllocation: {
title: '资金流向',
key: 'fundAllocation',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_fund_flow),
}),
providerSigner: {
title: '对方签约人',
key: 'providerSigner',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
readOnly: true,
placeholder: '请输入对方签约人',
},
rules: [{ required: true, message: '请输入对方签约人' }],
},
valueChange: {
immediate: true, // 是否立即执行一次
handle({ form }) {
form.fundAllocationName = getDictObj(
DICT_TYPE.contract_fund_flow,
form.fundAllocation,
)?.label;
ourStamp: {
title: '我方盖章人',
key: 'ourStamp',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
},
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{
getDictObj(DICT_TYPE.contract_fund_flow, form.fundAllocation)
?.label
}
</span>
);
ourStampDate: {
title: '我方盖章(签订)时间',
key: 'ourStampDate',
col: { span: 12 },
component: {
name: 'a-date-picker',
vModel: 'value',
valueFormat: 'YYYY-MM-DD',
},
},
rules: [{ required: true, message: '请选择资金流向' }],
},
fundDitch: {
title: '资金渠道',
key: 'fundDitch',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_funding_source),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{
getDictObj(DICT_TYPE.contract_funding_source, form.fundDitch)
?.label
}
</span>
);
ourStampName: {
title: '我方用章名称',
key: 'ourStampName',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
disabled: readOnly,
},
},
rules: [{ required: true, message: '请选择资金渠道' }],
},
budgetSum: {
title: '预算金额',
key: 'budgetSum',
col: { span: 8 },
colon: false,
component: {
name: 'a-input-number',
vModel: 'value',
class: 'w-full',
min: 0,
max: 9999,
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return <span class="">{form.budgetSum}</span>;
signPlace: {
title: '签订地点',
key: 'signPlace',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
},
},
},
priceType: {
title: '',
key: 'priceType',
col: { span: 6 },
labelCol: { style: { width: '12px' } },
colon: false,
component: {
name: 'fs-dict-select',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_currency_unit),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="mr-2">
{
getDictObj(
DICT_TYPE.contract_currency_unit,
form.priceType || '',
)?.label
}
</span>
);
effectType: {
title: '合同成立时生效',
key: 'effectType',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[180px]',
dict: dict({
getData: async () => {
return await getDictOptionsAsync(DICT_TYPE.common_whether);
},
}),
},
},
},
organiza: {
title: '组织形式',
key: 'organiza',
col: { span: 24 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_organization_form),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="">
{
getDictObj(DICT_TYPE.contract_organization_form, form.organiza)
?.label
}
</span>
);
buildDate: {
title: '合同成立时间',
key: 'buildDate',
col: { span: 12 },
component: {
name: 'a-date-picker',
vModel: 'value',
valueFormat: 'YYYY-MM-DD',
},
},
rules: [{ required: true, message: '请选择组织形式' }],
},
fileList: {
title: '相关附件',
key: 'fileList',
},
};
}

View File

@ -45,10 +45,11 @@ const isLoading = ref(false);
const contractTypeData = ref<any[]>([]);
const formBinding = ref({
col: { span: 24 },
labelCol: { style: { width: '120px' } },
initialForm: {},
columns: {},
...(({ columns: _, ...rest }) => rest)(
getFormSchema({
formRef,
}),
),
});
const formBindingByText = ref({
@ -293,7 +294,7 @@ onMounted(async () => {
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: !id.value || currData.value.step !== 'edit',
});
}).columns;
nextTick(() => {
formRef.value.setFormData(data);

View File

@ -1,7 +1,6 @@
import type { VxeGridPropTypes } from 'vxe-table';
import { dict } from '@fast-crud/fast-crud';
import dayjs from 'dayjs';
import { useRender } from '#/hooks/useRender';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
@ -82,9 +81,7 @@ export function getColumns(_params?: any): VxeGridPropTypes.Columns {
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
startDate: dayjs().startOf('month').format('YYYY-MM-DD'),
},
initialForm: {},
columns: {
contractName: {
title: '合同名称',

View File

@ -26,7 +26,7 @@ const gridOptions = reactive(
autoLoad: false,
ajax: {
query: async ({ page }) => {
const data = await Apis.contractBaseInfo.get_page({
const data = await Apis.qdSign.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,

View File

@ -1,182 +1,9 @@
<template>
<Page contentClass="h-full flex flex-col">
<a-space direction="vertical" size="small">
<a-card title="待办" size="small">
<vxe-grid ref="xGridRef" v-bind="gridOptions">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
<a-card title="已办" size="small" contentClass="">
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
</a-space>
</Page>
</template>
<script setup lang="ts">
import { defineComponent, ref, 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 {
type CreateCrudOptionsProps,
useColumns,
useFormWrapper,
useFs,
utils,
} from '@fast-crud/fast-crud';
import { MdiAdd, MdiUpdate, MdiDelete } from '@vben/icons';
import { dict } from "@fast-crud/fast-crud";
import Apis from '#/api'
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef:xGrid2Ref, triggerProxy:triggerProxy2 } = useVxeTable({ ref: 'xGrid2Ref' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_toDoPage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
/** Hooks - 表格 */
const grid2Options = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_donePage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
onMounted(() => {
})
let searchParams = reactive({})
const searchForm = ref({
columns: {
name: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
props: {
type: 'text',
showWordLimit: true,
},
},
title: '字典标签',
key: 'type',
autoSearchTrigger: 'enter',
show: true,
},
age: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
title: '字典键值',
key: 'value',
autoSearchTrigger: 'enter',
show: true,
},
},
onSearch(context: any) {
searchParams = context.form
triggerProxy('reload')
},
onReset(context: any) {
searchParams = context.form
},
});
//
import TodoPage from '../../components/todo-page/todo-page.vue';
</script>
<style></style>
<template>
<TodoPage :module="['contractSign']" />
</template>
<style scoped></style>

View File

@ -1,23 +1,93 @@
import Apis from '#/api';
import { router } from '#/router';
/**
*
* @param type
* @param id
*/
export function toDetail(type: string, id: string, params?: any) {
switch (type) {
case 'contractSetup': {
router.push(`/contract/approval/edit/${id}`);
break;
}
case 'selectMerchant': {
router.push(`/contract/business/edit/${id}`);
break;
}
default: {
break;
}
}
}
/**
*
* @param type
* @param id
*/
export function toDetailPage(type: string, id: string, params?: any) {
const { contractId } = params;
const { contractId } = params || {};
const name = '合同详情'; // 网页名称,可为空;
const iWidth = 1200; // 弹出窗口的宽度;
const iHeight = 800; // 弹出窗口的高度;
// window.screen.height获得屏幕的高window.screen.width获得屏幕的宽
const iTop = (window.screen.height - 30 - iHeight) / 2; // 获得窗口的垂直位置;
const iLeft = (window.screen.width - 10 - iWidth) / 2; // 获得窗口的水平位置;
const queryParams = new URLSearchParams();
if (type !== undefined) queryParams.append('type', type);
if (id !== undefined) queryParams.append('id', id);
if (contractId !== undefined) queryParams.append('contractId', contractId);
const url = `/iframe/contract/info?${queryParams.toString()}`;
window.open(
`/iframe/contract/info?type=${type}&id=${id}&contractId=${contractId}`,
url,
name,
`height=${iHeight},innerHeight=${iHeight},width=${iWidth},innerWidth=${
iWidth
},top=${iTop},left=${
iLeft
},toolbar=no,menubar=no,scrollbars=auto,resizable=no,location=no,status=no`,
`height=${iHeight},innerHeight=${iHeight},width=${iWidth},innerWidth=${iWidth},top=${iTop},left=${iLeft},toolbar=no,menubar=no,scrollbars=auto,resizable=no,location=no,status=no`,
);
}
/**
*
*/
export async function getContractTypes(parentId: string) {
try {
const contractReferTypeData = await Apis.contractReferType.get_list({
params: {},
});
return contractReferTypeData.rows
.map((item) => {
item.label = item.contrLevelName;
item.value = item.contrLevelId;
return item;
})
.filter((item) => item.parentId === parentId);
} catch (error) {
console.log(error);
return [];
}
}
/**
*
*/
export function filterContractTypes(
contractTypeData: any = [],
parentId: string,
) {
return contractTypeData
.map((item) => {
item.label = item.contrLevelName;
item.value = item.contrLevelId;
return item;
})
.filter((item) => {
if (parentId) {
return item.parentId === parentId;
}
return true;
});
}

View File

@ -7,6 +7,7 @@ import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { getTodoColumns } from '#/views/contract/schema';
import { toDetail, toDetailPage } from '#/views/contract/utils';
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef: xGrid2Ref, triggerProxy: triggerProxy2 } = useVxeTable({
@ -88,10 +89,6 @@ async function loadDataByDictType() {
treeData.value = [{ title: '全部', key: 'all', children: data }];
}
function toDetail(row) {}
function toDetailPage(row) {}
onMounted(() => {
loadDataByDictType();
});
@ -126,7 +123,7 @@ onMounted(() => {
<template #title_slot="{ row }">
<span
class="cursor-pointer text-blue-500 hover:underline"
@click="toDetail(row)"
@click="toDetail(row.module, row.businessId, row)"
>
{{ row.contractName }}
</span>
@ -136,7 +133,9 @@ onMounted(() => {
class="text-blue-500"
size="small"
type="text"
@click="toDetailPage(row)"
@click="
toDetailPage('approval', '', { contractId: row.contractId })
"
>
查看
</a-button>
@ -149,14 +148,16 @@ onMounted(() => {
size="small"
title="已办"
>
<vxe-grid ref="xGridRef" v-bind="grid2Options" class="flex-1">
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options" class="flex-1">
<template #toolbar_buttons> </template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="toDetailPage(row)"
@click="
toDetailPage('approval', '', { contractId: row.contractId })
"
>
查看
</a-button>

View File

@ -66,29 +66,50 @@ if (dictStore.initDict) {
}
.ant-checkbox-disabled .ant-checkbox-inner {
background: #fdfdfd;
background: #fafafa;
color: #333;
}
.ant-input-number-disabled {
background: #fafafa;
color: #333;
}
.ant-input-affix-wrapper-disabled,
.ant-input-affix-wrapper[disabled] {
background: #fdfdfd;
background: #fafafa;
color: #333;
}
.ant-radio-wrapper-disabled {
background: #fafafa;
color: #333;
}
.ant-radio-wrapper .ant-radio-disabled .ant-radio-inner {
background-color: rgba(50, 54, 57, 0.04);
border-color: hsl(240 5.9% 90%);
}
.ant-picker.ant-picker-disabled {
background: #fdfdfd;
background: #fafafa;
color: #333;
}
.ant-select-disabled.ant-select:not(.ant-select-customize-input)
.ant-select-selector {
background: #fafafa;
color: #333;
}
.ant-picker .ant-picker-input > input-disabled,
.ant-picker .ant-picker-input > input[disabled] {
background: #fdfdfd;
background: #fafafa;
color: #333 !important;
}
.ant-input-disabled,
.ant-input[disabled] {
background: #fdfdfd;
background: #fafafa;
color: #333;
}
</style>

View File

@ -1,18 +1,25 @@
<script lang="ts" setup>
import type { NotificationItem } from "@vben/layouts";
import type { NotificationItem } from '@vben/layouts';
import { computed, ref } from "vue";
import { storeToRefs, useAccessStore } from "@vben/stores";
import { computed, ref } from 'vue';
import { storeToRefs, useAccessStore, useUserStore } from '@vben/stores';
// import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
import { AuthenticationLoginExpiredModal } from "@vben/common-ui";
import { BasicLayout, LockScreen, Notification, UserDropdown } from "@vben/layouts";
import { preferences } from "@vben/preferences";
import { useUserStore } from "@vben/stores";
import { BookOpenText, CircleHelp, PhUserCircle } from "@vben/icons";
import { useRouter } from 'vue-router';
import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
import { PhUserCircle } from '@vben/icons';
import {
BasicLayout,
LockScreen,
Notification,
UserDropdown,
} from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { useAuthStore } from '#/store';
import { useAuthStore } from "#/store";
import { useRouter } from "vue-router";
const router = useRouter();
const notifications = ref<NotificationItem[]>([
@ -49,15 +56,17 @@ const notifications = ref<NotificationItem[]>([
const userStore = useUserStore();
const authStore = useAuthStore();
const accessStore = useAccessStore();
const showDot = computed(() => notifications.value.some((item) => !item.isRead));
const showDot = computed(() =>
notifications.value.some((item) => !item.isRead),
);
const menus = computed(() => [
{
handler: () => {
router.push("/user/center");
router.push('/user/center');
},
icon: PhUserCircle,
text: "个人中心",
text: '个人中心',
},
// {
// handler: () => {
@ -98,20 +107,20 @@ function handleMakeAll() {
}
function handleViewAll() {
console.log("viewAll");
router.push("/user/todo");
console.log('viewAll');
router.push('/user/todo');
}
const isDev = import.meta.env.MODE === 'development';
const value = ref(localStorage.getItem("@@@proxy_type") || ""); // /zp
const value = ref(localStorage.getItem('@@@proxy_type') || ''); // /zp
function handleMenuClick(e) {
console.log(e);
if (e.key == "pro") {
localStorage.setItem("@@@proxy_type", "");
if (e.key == 'pro') {
localStorage.setItem('@@@proxy_type', '');
} else {
localStorage.setItem("@@@proxy_type", "/" + e.key);
localStorage.setItem('@@@proxy_type', `/${e.key}`);
}
location.reload()
location.reload();
}
</script>
@ -130,7 +139,7 @@ function handleMenuClick(e) {
<template #notification>
<a-dropdown v-if="isDev">
<template #overlay>
<a-menu @click="handleMenuClick" selectable>
<a-menu selectable @click="handleMenuClick">
<a-menu-item key="pro"> 正式 </a-menu-item>
<a-menu-item key="czg"> czg </a-menu-item>
<a-menu-item key="zp"> zp </a-menu-item>
@ -138,7 +147,7 @@ function handleMenuClick(e) {
<a-menu-item key="xmh"> xmh </a-menu-item>
</a-menu>
</template>
<a-button> {{ value ? "代理" + value : "代理切换" }} </a-button>
<a-button> {{ value ? `代理${value}` : '代理切换' }} </a-button>
</a-dropdown>
<Notification
@ -160,7 +169,11 @@ function handleMenuClick(e) {
/>
</template>
<template #lock-screen>
<LockScreen :avatar :text="userStore.userInfo?.displayName" @to-login="handleLogout" />
<LockScreen
:avatar
:text="userStore.userInfo?.displayName"
@to-login="handleLogout"
/>
</template>
</BasicLayout>
</template>

View File

@ -1,2 +1,2 @@
export * from './auth';
export * from './dict'
export * from './dict';

View File

@ -1,4 +1,6 @@
/** 数据字典工具类 */
import { computed } from 'vue';
import Apis from '#/api';
import { useDictStore } from '#/store/dict';
import dataModule from '#/utils/dict/static.data';
@ -7,6 +9,10 @@ export * from './shared';
const dictStore = useDictStore();
const dictData = computed(() => {
return dictStore.dictMap;
});
/**
* dictType
*
@ -29,7 +35,7 @@ export interface DictDataOptions {
}
export function getDictDatas(dictType: string) {
return dictStore.getDictMap[dictType] || [];
return dictData.value[dictType] || [];
}
export function getDictOpts(dictType: string) {
@ -58,7 +64,7 @@ export async function getDictDatasAsync(dictTypes: string[]) {
dictDataMap[dictType].push({
...dictData,
value: dictData.value,
label: dictData.name,
label: dictData.label,
colorType: dictData.colorType,
cssClass: dictData.cssClass,
} as DictDataType);
@ -99,8 +105,7 @@ export function getDictOptions(
): any[] {
const dictOption: DictDataType[] = [];
valueType ||= 'string';
const dictOptions: DictDataType[] = getDictDatas(dictType);
const dictOptions: DictDataType[] = dictData.value[dictType] || [];
if (dictOptions && dictOptions.length > 0) {
dictOptions.forEach((dict: DictDataType) => {
dictOption.push({
@ -166,6 +171,42 @@ export function getDictObj(dictType: string, value: any): DictDataType | null {
}
}
/** 获取指定 value 的字典数据 */
export function getDictObjByOptions(
options: DictDataType[],
value: any,
): DictDataType | null {
if (options) {
if (value) {
const result = options.find((dict: DictDataType) => dict.value === value);
return result || null;
}
return null;
} else {
return null;
}
}
/** 获取指定 value 的字典数据 */
export async function getDictObjAsync(
dictType: string,
value: any,
): Promise<DictDataType | null> {
const dictOptions = await getDictOptionsAsync(dictType);
if (dictOptions) {
if (value) {
return (
dictOptions.find(
(dict: DictDataType) => dict.value === value.toString(),
) || null
);
}
return null;
} else {
return null;
}
}
/** 获取字典默认数据 */
export function getDictDefaultObj(dictType: string): DictDataType | null {
const dictOptions: DictDataType[] = getDictDatas(dictType);

View File

@ -1,12 +1,15 @@
<script lang="tsx" setup>
import { reactive, ref, nextTick } from "vue";
import { useVbenModal } from "@vben/common-ui";
import dayjs from "dayjs";
import Apis from "#/api";
import chooseUserModal from "#/views/system/user/choose-user-modal.vue";
import { nextTick, reactive, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import dayjs from 'dayjs';
import Apis from '#/api';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
const emit = defineEmits<{
(e: "success"): void;
(e: 'success'): void;
}>();
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
@ -16,210 +19,210 @@ const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
const data = ref({});
const formRef = ref();
const selectField = ref("");
const selectField = ref('');
const formBinding = ref({
col: { span: 24 },
initialForm: {
dutyDate: dayjs().format("YYYY-MM-DD"),
dutyDate: dayjs().format('YYYY-MM-DD'),
},
labelPosition: "top",
labelPosition: 'top',
columns: {
dutyDate: {
title: "值班日期",
key: "dutyDate",
title: '值班日期',
key: 'dutyDate',
component: {
name: "a-date-picker",
vModel: "value",
name: 'a-date-picker',
vModel: 'value',
allowClear: true,
props: {
format: "YYYY-MM-DD",
valueFormat: "YYYY-MM-DD",
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
},
},
rules: [{ required: true, message: "请选择值班日期" }],
rules: [{ required: true, message: '请选择值班日期' }],
},
zzb: {
colon: false,
class:'!mb-2',
class: '!mb-2',
render: () => {
return <a-divider orientation="left">总值班</a-divider>;
},
},
dutyAllPeople: {
title: "人员选择",
key: "dutyAllPeople",
title: '人员选择',
key: 'dutyAllPeople',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {
readOnly: true,
},
onClick: () => {
selectField.value = "dutyAll";
selectField.value = 'dutyAll';
chooseUserModalApi.open();
},
},
rules: [{ required: true, message: "请选择人员" }],
rules: [{ required: true, message: '请选择人员' }],
},
dutyAllTelphone: {
title: "联系方式",
key: "dutyAllTelphone",
title: '联系方式',
key: 'dutyAllTelphone',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {},
},
rules: [{ required: true, message: "请填写联系方式" }],
rules: [{ required: true, message: '请填写联系方式' }],
},
dutyAllPhone: {
title: "办公室电话",
key: "dutyAllPhone",
title: '办公室电话',
key: 'dutyAllPhone',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {},
},
rules: [{ required: true, message: "请填写办公室电话" }],
rules: [{ required: true, message: '请填写办公室电话' }],
},
jgbmld: {
colon: false,
class:'!mb-2',
class: '!mb-2',
render: () => {
return <a-divider orientation="left">机关部门领导</a-divider>;
},
},
dispatchPeople: {
title: "人员选择",
key: "dispatchPeople",
title: '人员选择',
key: 'dispatchPeople',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {
readOnly: true,
},
onClick: () => {
selectField.value = "dispatch";
selectField.value = 'dispatch';
chooseUserModalApi.open();
},
},
rules: [{ required: true, message: "请选择人员" }],
rules: [{ required: true, message: '请选择人员' }],
},
dispatchTelphone: {
title: "联系方式",
key: "dispatchTelphone",
title: '联系方式',
key: 'dispatchTelphone',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {},
},
rules: [{ required: true, message: "请填写联系方式" }],
rules: [{ required: true, message: '请填写联系方式' }],
},
dispatchPhone: {
title: "办公室电话",
key: "dispatchPhone",
title: '办公室电话',
key: 'dispatchPhone',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {},
},
rules: [{ required: true, message: "请填写办公室电话" }],
rules: [{ required: true, message: '请填写办公室电话' }],
},
zb: {
colon: false,
class:'!mb-2',
class: '!mb-2',
render: () => {
return <a-divider orientation="left">值班</a-divider>;
},
},
dutyPeople: {
title: "人员选择",
key: "dutyPeople",
title: '人员选择',
key: 'dutyPeople',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {
readOnly: true,
},
onClick: () => {
selectField.value = "duty";
selectField.value = 'duty';
chooseUserModalApi.open();
},
},
rules: [{ required: true, message: "请选择人员" }],
rules: [{ required: true, message: '请选择人员' }],
},
dutyTelphone: {
title: "联系方式",
key: "dutyTelphone",
title: '联系方式',
key: 'dutyTelphone',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {},
},
rules: [{ required: true, message: "请填写联系方式" }],
rules: [{ required: true, message: '请填写联系方式' }],
},
dutyPhone: {
title: "办公室电话",
key: "dutyPhone",
title: '办公室电话',
key: 'dutyPhone',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {},
},
rules: [{ required: true, message: "请填写办公室电话" }],
rules: [{ required: true, message: '请填写办公室电话' }],
},
sj: {
colon: false,
class:'!mb-2',
class: '!mb-2',
render: () => {
return <a-divider orientation="left">司机</a-divider>;
},
},
driver: {
title: "司机",
key: "driver",
title: '司机',
key: 'driver',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {},
},
rules: [{ required: true, message: "请输入司机姓名" }],
rules: [{ required: true, message: '请输入司机姓名' }],
},
driverTelphone: {
title: "联系方式",
key: "driverTelphone",
title: '联系方式',
key: 'driverTelphone',
col: { span: 8 },
component: {
name: "a-input",
vModel: "value",
name: 'a-input',
vModel: 'value',
props: {},
},
rules: [{ required: true, message: "请填写联系方式" }],
rules: [{ required: true, message: '请填写联系方式' }],
},
bz: {
colon: false,
class:'!mb-2',
class: '!mb-2',
render: () => {
return <a-divider orientation="left">值班备注</a-divider>;
},
},
remark: {
title: "备注",
key: "remark",
title: '备注',
key: 'remark',
col: { span: 24 },
component: {
name: "a-textarea",
vModel: "value",
name: 'a-textarea',
vModel: 'value',
props: {},
},
},
@ -227,7 +230,7 @@ const formBinding = ref({
async doSubmit(context: any) {
console.log(context);
await Apis.zbgl.post_save({ data: context.form });
emit("success");
emit('success');
modalApi.close();
},
});
@ -238,8 +241,8 @@ function handleUserRowClick(row) {
peoples[selectField.value] = row;
console.log(formRef.value);
formRef.value?.setFormData({
[selectField.value + "People"]: row.label,
[selectField.value + "Telphone"]: row.mobile,
[`${selectField.value}People`]: row.label,
[`${selectField.value}Telphone`]: row.mobile,
});
console.log(peoples);
console.log(formRef.value?.form);
@ -259,7 +262,7 @@ const [Modal, modalApi] = useVbenModal({
}
},
onConfirm() {
console.info("onConfirm");
console.info('onConfirm');
console.log(formRef.value?.form);
formRef.value?.submit();
},
@ -271,13 +274,12 @@ const [Modal, modalApi] = useVbenModal({
<template>
<Modal :title="data.isUpdate ? '修改值班信息' : '新增值班信息'">
<ChooseUserModal class="w-[950px]" @row-click="handleUserRowClick" />
<fs-form ref="formRef" v-bind="formBinding"> </fs-form>
<fs-form ref="formRef" v-bind="formBinding" />
</Modal>
</template>
<style scoped>
:deep(.ant-divider-horizontal.ant-divider-with-text){
:deep(.ant-divider-horizontal.ant-divider-with-text) {
margin: 0 !important;
}
</style>