This commit is contained in:
parent
7de10e44c1
commit
9b798ae44d
|
@ -95,6 +95,8 @@ export const useUserStore = defineStore(
|
|||
await redirectFromLogin();
|
||||
}
|
||||
console.log(userInfo);
|
||||
userInfo.userName = userInfo.gwmc;
|
||||
|
||||
if (routeStore.isInitAuthRoute) {
|
||||
window.$notification?.success({
|
||||
title: $t('page.login.common.loginSuccess'),
|
||||
|
|
|
@ -22,17 +22,9 @@ declare module 'vue' {
|
|||
FullScreen: typeof import('./../components/common/full-screen.vue')['default']
|
||||
IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
|
||||
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
||||
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
||||
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
||||
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
||||
'IconIc:roundPlus': typeof import('~icons/ic/round-plus')['default']
|
||||
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
|
||||
IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
|
||||
IconIcRoundRefresh: typeof import('~icons/ic/round-refresh')['default']
|
||||
IconIcRoundRemove: typeof import('~icons/ic/round-remove')['default']
|
||||
IconIcRoundSearch: typeof import('~icons/ic/round-search')['default']
|
||||
IconLocalBanner: typeof import('~icons/local/banner')['default']
|
||||
IconMdiAccountCheck: typeof import('~icons/mdi/account-check')['default']
|
||||
IconMdiArchiveCancelOutline: typeof import('~icons/mdi/archive-cancel-outline')['default']
|
||||
IconMdiArchiveOutline: typeof import('~icons/mdi/archive-outline')['default']
|
||||
IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
|
||||
|
@ -45,11 +37,9 @@ declare module 'vue' {
|
|||
IconMdiChevronUp: typeof import('~icons/mdi/chevron-up')['default']
|
||||
IconMdiClose: typeof import('~icons/mdi/close')['default']
|
||||
IconMdiCloudUpload: typeof import('~icons/mdi/cloud-upload')['default']
|
||||
IconMdiContentSave: typeof import('~icons/mdi/content-save')['default']
|
||||
IconMdiContentSaveOutline: typeof import('~icons/mdi/content-save-outline')['default']
|
||||
IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
|
||||
IconMdiDownload: typeof import('~icons/mdi/download')['default']
|
||||
IconMdiDrag: typeof import('~icons/mdi/drag')['default']
|
||||
IconMdiDragVariant: typeof import('~icons/mdi/drag-variant')['default']
|
||||
IconMdiExport: typeof import('~icons/mdi/export')['default']
|
||||
IconMdiEye: typeof import('~icons/mdi/eye')['default']
|
||||
|
@ -58,10 +48,10 @@ declare module 'vue' {
|
|||
IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
||||
IconMdiNotificationsNone: typeof import('~icons/mdi/notifications-none')['default']
|
||||
IconMdiPlus: typeof import('~icons/mdi/plus')['default']
|
||||
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
||||
IconMdiRun: typeof import('~icons/mdi/run')['default']
|
||||
IconMdiSend: typeof import('~icons/mdi/send')['default']
|
||||
IconMdiSquareEditOutline: typeof import('~icons/mdi/square-edit-outline')['default']
|
||||
IconMdiSync: typeof import('~icons/mdi/sync')['default']
|
||||
IconMdiUndo: typeof import('~icons/mdi/undo')['default']
|
||||
IconMdiUndoVariant: typeof import('~icons/mdi/undo-variant')['default']
|
||||
IconUilSearch: typeof import('~icons/uil/search')['default']
|
||||
|
@ -80,7 +70,6 @@ declare module 'vue' {
|
|||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
|
||||
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
||||
NDataTable: typeof import('naive-ui')['NDataTable']
|
||||
NDatePicker: typeof import('naive-ui')['NDatePicker']
|
||||
NDescriptions: typeof import('naive-ui')['NDescriptions']
|
||||
NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem']
|
||||
|
@ -89,16 +78,13 @@ declare module 'vue' {
|
|||
NDrawer: typeof import('naive-ui')['NDrawer']
|
||||
NDrawerContent: typeof import('naive-ui')['NDrawerContent']
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
||||
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||
NForm: typeof import('naive-ui')['NForm']
|
||||
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||
NGi: typeof import('naive-ui')['NGi']
|
||||
NGrid: typeof import('naive-ui')['NGrid']
|
||||
NGridItem: typeof import('naive-ui')['NGridItem']
|
||||
NH3: typeof import('naive-ui')['NH3']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NIconWrapper: typeof import('naive-ui')['NIconWrapper']
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
|
@ -112,7 +98,6 @@ declare module 'vue' {
|
|||
NModal: typeof import('naive-ui')['NModal']
|
||||
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
||||
NP: typeof import('naive-ui')['NP']
|
||||
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
|
||||
NPopover: typeof import('naive-ui')['NPopover']
|
||||
NProgress: typeof import('naive-ui')['NProgress']
|
||||
NRadio: typeof import('naive-ui')['NRadio']
|
||||
|
|
|
@ -0,0 +1,470 @@
|
|||
<script setup lang="ts">
|
||||
import { reactive, ref } from "vue";
|
||||
import { useModal } from "@/components/Modal";
|
||||
import type { FormSchema } from "@/components/Form";
|
||||
import { BasicForm, useForm } from "@/components/Form";
|
||||
import ChooseMenuModal from "@/views/canteen/menu/modules/ChooseMenuModal.vue";
|
||||
import MenuCard from "@/views/canteen/menu/modules/MenuCard.vue";
|
||||
import { DICT_TYPE } from "@/utils/dict";
|
||||
import { addRecipe, getRecipeList, updateRecipe } from "@/api/office/canteen";
|
||||
import { getColumns, PrimaryKey } from "./schema";
|
||||
import dayjs from "dayjs";
|
||||
import isoWeek from 'dayjs/plugin/isoWeek'
|
||||
import { usePagination } from 'alova/client';
|
||||
import { useVxeTable } from "@/hooks/common/vxeTable";
|
||||
import { SolarDay } from "tyme4ts";
|
||||
import { paginationProps } from "@/utils/alova";
|
||||
|
||||
dayjs.extend(isoWeek);
|
||||
|
||||
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: "xGridRef" });
|
||||
|
||||
|
||||
const chooseMenuModalRef = ref();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "register"): void;
|
||||
(e: "success"): void;
|
||||
}>();
|
||||
|
||||
const [modalRegister, { openModal, closeModal, setModalProps }] = useModal({
|
||||
style: {
|
||||
width: "950px",
|
||||
},
|
||||
});
|
||||
|
||||
const formSchema = ref<FormSchema[]>([
|
||||
{
|
||||
field: PrimaryKey,
|
||||
component: "NInput",
|
||||
label: "主键",
|
||||
show: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: "recipeDate",
|
||||
component: "NInput",
|
||||
label: "日期",
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
field: "recipeId",
|
||||
component: "NInput",
|
||||
label: "菜品ID",
|
||||
show: false,
|
||||
},
|
||||
// {
|
||||
// field: 'stapleFood',
|
||||
// component: 'DictTag',
|
||||
// componentProps: {
|
||||
// type: DICT_TYPE.canteen_staplefood,
|
||||
// selectable: true
|
||||
// },
|
||||
// label: '主食',
|
||||
// rules: [{ required: true, message: '请选择主食' }]
|
||||
// },
|
||||
{
|
||||
field: "eatinRecipe",
|
||||
component: "NInputTextArea",
|
||||
label: "堂食菜品",
|
||||
// defaultValue: '',
|
||||
componentProps: {
|
||||
placeholder: "请输入菜品,可用逗号分隔",
|
||||
},
|
||||
// rules: [{ required: true, message: '请输入堂食菜品' }],
|
||||
},
|
||||
{
|
||||
field: "eatinOpen",
|
||||
label: "堂食开放状态",
|
||||
component: "NRadioGroup",
|
||||
defaultValue: true,
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: "开启",
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
label: "关闭",
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
field: "deliveryRecipe",
|
||||
label: "外送菜品",
|
||||
component: "NInputTextArea",
|
||||
// defaultValue: '',
|
||||
componentProps: {
|
||||
placeholder: "请输入菜品,可用逗号分隔",
|
||||
},
|
||||
// rules: [{ required: true, message: '请输入堂食菜品' }],
|
||||
},
|
||||
{
|
||||
field: "deliveryOpen",
|
||||
label: "外送开放状态",
|
||||
component: "NRadioGroup",
|
||||
defaultValue: true,
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: "开启",
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
label: "关闭",
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
field: "remarks",
|
||||
component: "NInputTextArea",
|
||||
label: "备注",
|
||||
defaultValue: "",
|
||||
componentProps: {
|
||||
placeholder: "",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const [register, { setFieldsValue, validate, resetFields, getFieldsValue }] = useForm({
|
||||
gridProps: { xGap: "24", cols: "1" },
|
||||
// isFull:true,
|
||||
inline: true,
|
||||
labelWidth: 120,
|
||||
collapsedRows: 200,
|
||||
// collapsedRows:999,
|
||||
showAdvancedButton: true,
|
||||
showActionButtonGroup: false,
|
||||
schemas: formSchema,
|
||||
});
|
||||
|
||||
|
||||
function getDatesBetween(startDate, endDate) {
|
||||
const dates = [];
|
||||
let currentDate = dayjs(startDate);
|
||||
|
||||
while (currentDate.isBefore(endDate) || currentDate.isSame(endDate, 'day')) {
|
||||
dates.push(currentDate.format('YYYY-MM-DD'));
|
||||
currentDate = currentDate.add(1, 'day');
|
||||
}
|
||||
|
||||
return dates;
|
||||
}
|
||||
|
||||
const searchParams = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 100
|
||||
});
|
||||
|
||||
/** Hooks - 数据请求 */
|
||||
const { send, onSuccess } = usePagination(
|
||||
({ pageNum, pageSize }: any) => getRecipeList({ ...searchParams }),
|
||||
{ ...paginationProps(), immediate: false }
|
||||
);
|
||||
|
||||
onSuccess((res: any) => {
|
||||
// 生成当前年月的每一天,组成数组
|
||||
var start = dayjs(weekValue.value[0]).date();
|
||||
var end = dayjs(weekValue.value[1]).date();
|
||||
let arr = [];
|
||||
|
||||
for (const item of getDatesBetween(weekValue.value[0], weekValue.value[1])) {
|
||||
|
||||
let obj = {
|
||||
recipeDate: item,
|
||||
week: "",
|
||||
remarks: "",
|
||||
};
|
||||
|
||||
const solar = SolarDay.fromYmd(
|
||||
dayjs(item).year(),
|
||||
dayjs(item).month() + 1,
|
||||
dayjs(item).date()
|
||||
);
|
||||
const holiday = solar.getLegalHoliday();
|
||||
|
||||
var datas = dayjs(obj.recipeDate).day();
|
||||
var week = ["日", "一", "二", "三", "四", "五", "六"];
|
||||
obj.week = "星期" + week[datas];
|
||||
obj.eatinOpen = true;
|
||||
obj.deliveryOpen = true;
|
||||
if (holiday) {
|
||||
obj.week = obj.week + "(" + holiday.name + ")";
|
||||
}
|
||||
if (datas == 0 || datas == 6 || holiday) {
|
||||
obj.eatinOpen = false;
|
||||
obj.deliveryOpen = false;
|
||||
}
|
||||
|
||||
arr.push(obj);
|
||||
}
|
||||
|
||||
for (let m of arr) {
|
||||
for (const item of res.data.rows) {
|
||||
item.recipeDate = dayjs(item.recipeDate).format("YYYY-MM-DD");
|
||||
if (item.recipeDate === m.recipeDate) {
|
||||
console.log("日期:", item.recipeDate, item);
|
||||
if (["0", "1"].includes(item.deliveryOpen)) {
|
||||
item.deliveryOpen = Boolean(Number(item.deliveryOpen));
|
||||
}
|
||||
if (["0", "1"].includes(item.eatinOpen)) {
|
||||
item.eatinOpen = Boolean(Number(item.eatinOpen));
|
||||
}
|
||||
Object.assign(m, item);
|
||||
// m = item
|
||||
}
|
||||
}
|
||||
}
|
||||
res.data.rows = arr;
|
||||
});
|
||||
|
||||
/** Hooks - 表格 */
|
||||
const gridOptions = reactive(
|
||||
gridProps({
|
||||
columns: getColumns(),
|
||||
pagerConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
proxyConfig: {
|
||||
autoLoad: true,
|
||||
ajax: {
|
||||
query: ({ page }) => send({ pageNum: page.currentPage, pageSize: page.pageSize }),
|
||||
},
|
||||
},
|
||||
toolbarConfig: {
|
||||
enabled: false
|
||||
},
|
||||
rowStyle({ row, rowIndex }) {
|
||||
if ((row && ["星期六", "星期日"].includes(row.week)) || row.week.length > 3) {
|
||||
return {
|
||||
backgroundColor: "#fbfbfb",
|
||||
};
|
||||
}
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
interface WeekData {
|
||||
weekNumber: number;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
}
|
||||
function getLastWeeksData(weeks: number = 6): WeekData[] {
|
||||
const result: WeekData[] = [];
|
||||
|
||||
for (let i = weeks; i > 0; i--) {
|
||||
const weekStart = dayjs().subtract(i, 'week').startOf('isoWeek');
|
||||
const weekEnd = dayjs().subtract(i, 'week').endOf('isoWeek');
|
||||
const weekNumber = weekStart.isoWeek();
|
||||
|
||||
result.push({
|
||||
weekNumber,
|
||||
startDate: weekStart.format('YYYY-MM-DD'),
|
||||
endDate: weekEnd.format('YYYY-MM-DD')
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getNextWeeksData(weeks: number = 2): WeekData[] {
|
||||
const result: WeekData[] = [];
|
||||
|
||||
for (let i = 0; i <= weeks; i++) {
|
||||
const weekStart = dayjs().add(i, 'week').startOf('isoWeek');
|
||||
const weekEnd = dayjs().add(i, 'week').endOf('isoWeek');
|
||||
const weekNumber = weekStart.isoWeek();
|
||||
|
||||
result.push({
|
||||
weekNumber,
|
||||
startDate: weekStart.format('YYYY-MM-DD'),
|
||||
endDate: weekEnd.format('YYYY-MM-DD'),
|
||||
value: `${weekStart.format('YYYY-MM-DD')},${weekEnd.format('YYYY-MM-DD')}`,
|
||||
label: `第${weekNumber}周 ( ${weekStart.format('YYYY-MM-DD')} 至 ${weekEnd.format('YYYY-MM-DD')} )`
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
|
||||
if (!weekNumber) {
|
||||
window.$message?.error("请选择请选择需要同步的某周");
|
||||
return
|
||||
}
|
||||
|
||||
if (!currWeek.value) {
|
||||
window.$message?.error("请选择需要同步至某周");
|
||||
return
|
||||
}
|
||||
|
||||
let fullData = xGridRef.value?.getTableData().fullData || []
|
||||
if (fullData.length != 7) {
|
||||
window.$message?.error("请选择完整的一周");
|
||||
return
|
||||
}
|
||||
|
||||
setModalProps({ confirmLoading: true });
|
||||
console.log('[ currWeek.value ] >', currWeek.value)
|
||||
console.log('[ fullData ] >', fullData)
|
||||
let week = currWeek.value.split(",")
|
||||
let arr = getDatesBetween(week[0], week[1])
|
||||
console.log('[ arr ] >', arr)
|
||||
let newArr = []
|
||||
let i = 0;
|
||||
for (const old of fullData) {
|
||||
old.recipeDate = arr[i];
|
||||
old.eatinOpen = old.eatinOpen == true ? 1 : 0;
|
||||
old.deliveryOpen = old.deliveryOpen == true ? 1 : 0;
|
||||
i++
|
||||
newArr.push(old)
|
||||
}
|
||||
await Apis.erp.post_recipe_savebatch({ data: newArr });
|
||||
|
||||
emit("success");
|
||||
closeModal();
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
function handleUserRowClick(row) {
|
||||
console.log(row);
|
||||
setFieldsValue({ jlry: row.name });
|
||||
}
|
||||
|
||||
function handleMenuItemClick(e) {
|
||||
console.log(e);
|
||||
}
|
||||
const currQtsb = ref({});
|
||||
const currData = ref<Recordable>({});
|
||||
|
||||
const isUpdate = ref(false);
|
||||
|
||||
const selectMenus = ref([]);
|
||||
function handleMenuConfirm(e) {
|
||||
console.log(e);
|
||||
selectMenus.value = e;
|
||||
setFieldsValue({
|
||||
recipe: e.map((item) => item.dish).join(","),
|
||||
recipeId: e.map((item) => item.dishId).join(","),
|
||||
});
|
||||
}
|
||||
|
||||
const weeks = ref<WeekData[]>([])
|
||||
|
||||
const weeks2 = ref<WeekData[]>([])
|
||||
const currWeek = ref()
|
||||
|
||||
const weekNumber = ref();
|
||||
const weekValue = ref<string[]>([]);
|
||||
function setWeek(week: WeekData) {
|
||||
weekNumber.value = week.weekNumber
|
||||
weekValue.value = [week.startDate, week.endDate]
|
||||
triggerProxy('reload')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
/** 打开弹窗 */
|
||||
open: (data: AnyObject) => {
|
||||
isUpdate.value = Boolean(data?.isUpdate);
|
||||
openModal();
|
||||
weeks.value = getLastWeeksData()
|
||||
|
||||
weeks2.value = getNextWeeksData()
|
||||
|
||||
// console.log('[ getLastWeeksData ] >', getLastWeeksData())
|
||||
setTimeout(() => {
|
||||
setFieldsValue(currData.value);
|
||||
}, 45);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<BasicModal :title="'同步指定周的菜谱'" @register="modalRegister" @on-ok="handleSubmit">
|
||||
<template #default>
|
||||
|
||||
<div class="flex flex-row h-600px">
|
||||
|
||||
<div>
|
||||
<span class="mt-2 block">请选择需要同步的某周菜谱,右侧可以预览,仅支持近6周</span>
|
||||
|
||||
<NGrid class="" cols="1" responsive="screen" :x-gap="12" :y-gap="9">
|
||||
<NGi>
|
||||
<NCard :segmented="{ content: true }" content-style="padding: 0;" :bordered="false" size="small"
|
||||
title="">
|
||||
<div class="flex flex-wrap project-card">
|
||||
<template v-for="(item, index) in weeks" :key="index">
|
||||
<n-card size="small" :title="'第' + item.weekNumber + '周'"
|
||||
class="cursor-pointer project-card-item "
|
||||
:class="weekNumber == item.weekNumber ? 'bg-blue-200!' : ''" hoverable @click="setWeek(item)">
|
||||
<div class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-lx text-center">{{ item.startDate + ' 至 ' + item.endDate }}</span>
|
||||
</div>
|
||||
</n-card>
|
||||
</template>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<span class="mt-6 block">需要同步至</span>
|
||||
|
||||
<NSelect v-model:value="currWeek" placeholder="请选择需要同步至的周数" :options="weeks2"></NSelect>
|
||||
|
||||
<span class="mt-6 block">选中周所对应菜谱预览</span>
|
||||
|
||||
<div class="w-850px h-300px">
|
||||
<VxeGrid ref="xGridRef" v-bind="gridOptions">
|
||||
|
||||
<template #openTsSlot="{ row }">
|
||||
<div>
|
||||
<n-checkbox v-model:checked="row.eatinOpen" disabled>
|
||||
</n-checkbox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #openDcSlot="{ row }">
|
||||
<div>
|
||||
<n-checkbox v-model:checked="row.deliveryOpen" disabled>
|
||||
</n-checkbox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</VxeGrid>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</BasicModal>
|
||||
<ChooseMenuModal ref="chooseMenuModalRef" @confirm="handleMenuConfirm" @itemClick="handleMenuItemClick">
|
||||
</ChooseMenuModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.readonly .n-input__textarea-el) {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.project-card {
|
||||
margin-right: -6px;
|
||||
}
|
||||
|
||||
.project-card-item {
|
||||
margin: -1px;
|
||||
width: 16.6666%;
|
||||
}
|
||||
</style>
|
|
@ -12,7 +12,7 @@ import dayjs from "dayjs";
|
|||
import { getMonthStartAndEnd, shortcuts } from "@/utils/time";
|
||||
import { useVxeTable } from "@/hooks/common/vxeTable";
|
||||
import { SolarDay } from "tyme4ts";
|
||||
|
||||
import RecipeSyncModal from "./RecipeSyncModal.vue";
|
||||
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: "xGridRef" });
|
||||
|
||||
const searchParams = reactive({
|
||||
|
@ -145,6 +145,7 @@ const monthArr = computed(() => {
|
|||
|
||||
const editModalRef = ref();
|
||||
const uploadModalRef = ref();
|
||||
const syncModalRef = ref();
|
||||
|
||||
function openEditModal(record?: Recordable) {
|
||||
console.log(record);
|
||||
|
@ -191,6 +192,14 @@ function handleOpenExport() {
|
|||
exportSearchParams.daterange = getMonthStartAndEnd(searchParams.recipeDate);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 打开同步至某周弹窗
|
||||
*/
|
||||
function handleOpenSyncModal() {
|
||||
syncModalRef.value?.open();
|
||||
}
|
||||
|
||||
const checkedValue = ref<string | null>("daterange");
|
||||
const exportSearchParams = reactive<any>({
|
||||
daterange: getMonthStartAndEnd(),
|
||||
|
@ -267,7 +276,7 @@ function handleOpenUploadModal() {
|
|||
:class="{ 'thing-cell-on': searchParams.recipeDate == item }" @click="handleMonthChange(item)">
|
||||
<template #header>{{
|
||||
item == dayjs().format("YYYY-MM") ? item + "(当月)" : item
|
||||
}}</template>
|
||||
}}</template>
|
||||
</n-thing>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
|
@ -295,6 +304,14 @@ function handleOpenUploadModal() {
|
|||
</template>
|
||||
导出
|
||||
</NButton>
|
||||
|
||||
<NButton type="info" @click="handleOpenSyncModal()">
|
||||
<template #icon>
|
||||
<icon-mdi-sync />
|
||||
</template>
|
||||
同步指定周的菜谱
|
||||
</NButton>
|
||||
|
||||
<!-- <BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" /> -->
|
||||
</NSpace>
|
||||
</template>
|
||||
|
@ -349,6 +366,8 @@ function handleOpenUploadModal() {
|
|||
<RecipeEditModal ref="editModalRef" @success="triggerProxy('reload')">
|
||||
</RecipeEditModal>
|
||||
|
||||
<RecipeSyncModal ref="syncModalRef" @success="triggerProxy('reload')"></RecipeSyncModal>
|
||||
|
||||
<RecipeUploadModal ref="uploadModalRef"></RecipeUploadModal>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -134,6 +134,7 @@ onContractTypeSuccess((res: any) => {
|
|||
|
||||
/** Hooks - 表格 */
|
||||
const gridOptions = reactive(gridProps({
|
||||
height: "300px",
|
||||
columns: [
|
||||
{ type: 'seq', title: '序号', width: 60 },
|
||||
{ field: 'referenceName', title: '签约依据名称', minWidth: 150 },
|
||||
|
@ -350,8 +351,10 @@ function handleBack() {
|
|||
合同类别
|
||||
<span v-if="isRequired('ctrType')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="h-80px overflow-y-auto">
|
||||
<DictTag v-model:value="currData.ctrType" :options="filterContractTypes('-1')" selectable> </DictTag>
|
||||
<div class="">
|
||||
<NSelect v-model:value="currData.ctrType" class="w-400px" :options="filterContractTypes('-1')"
|
||||
placeholder="请选择合同类别" @update:value="() => currData.ctrTwoType = null">
|
||||
</NSelect>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
|
@ -360,10 +363,10 @@ function handleBack() {
|
|||
二级类别
|
||||
<span v-if="isRequired('ctrTwoType')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="h-80px overflow-y-auto">
|
||||
<DictTag v-model:value="currData.ctrTwoType" :options="filterContractTypes(currData.ctrType)" selectable
|
||||
<div class="">
|
||||
<NSelect v-model:value="currData.ctrTwoType" :options="filterContractTypes(contractData.ctrType)"
|
||||
placeholder="请选择二级类别">
|
||||
</DictTag>
|
||||
</NSelect>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
|
|
|
@ -19,8 +19,11 @@ import { useTabStore } from "@/store/modules/tab";
|
|||
|
||||
import { FileUploader } from "@/utils/file";
|
||||
import { FileSource } from "@/enums";
|
||||
import { forEach } from "lodash-es";
|
||||
|
||||
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: 'xGridRef' });
|
||||
const { xGridRef: xGridRef2 } = useVxeTable({ ref: 'xGridRef2' });
|
||||
|
||||
|
||||
const PrimaryKey = "guid"
|
||||
const message = useMessage();
|
||||
|
@ -61,8 +64,28 @@ const fileUploader = new FileUploader({
|
|||
},
|
||||
})
|
||||
|
||||
|
||||
/** 必填字段校验 */
|
||||
const requiredFieldRules: any = {
|
||||
"projectNum": { required: true, message: '请选择项目' },
|
||||
"projectProp": { required: true, message: '请选择项目类别' },
|
||||
"projectNameId": { required: true, message: '请选择项目名称' },
|
||||
"priceStyleId": { required: true, message: '请选择商务计价方式' },
|
||||
"fundDitch": { required: true, message: '资金渠道不得为空' },
|
||||
"organiza": { required: true, message: '组织形式不得为空' },
|
||||
}
|
||||
|
||||
/** 必填字段校验,如果是必填字段则返回对应message */
|
||||
function isRequired(field: string): string {
|
||||
let rule = requiredFieldRules[field];
|
||||
if (rule && rule.required) {
|
||||
return rule.message || `${field}不可为空`;
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
/** 必填字段校验 */
|
||||
const requiredFieldRulesByContractBase: any = {
|
||||
"contractName": { required: true, message: '合同名称不得为空' },
|
||||
"ctrType": { required: true, message: '合同类别不得为空' },
|
||||
"ctrTwoType": { required: true, message: '合同二级类别不得为空' },
|
||||
|
@ -72,7 +95,7 @@ const requiredFieldRules: any = {
|
|||
}
|
||||
|
||||
/** 必填字段校验,如果是必填字段则返回对应message */
|
||||
function isRequired(field: string): string {
|
||||
function isRequiredByContractBase(field: string): string {
|
||||
let rule = requiredFieldRules[field];
|
||||
if (rule && rule.required) {
|
||||
return rule.message || `${field}不可为空`;
|
||||
|
@ -128,6 +151,7 @@ onContractTypeSuccess((res: any) => {
|
|||
|
||||
/** Hooks - 表格 */
|
||||
const gridOptions = reactive(gridProps({
|
||||
height: "300px",
|
||||
columns: [
|
||||
{ type: 'seq', title: '序号', width: 60 },
|
||||
{ field: 'referenceName', title: '签约依据名称', minWidth: 150 },
|
||||
|
@ -148,6 +172,26 @@ const gridOptions = reactive(gridProps({
|
|||
}
|
||||
}));
|
||||
|
||||
/** Hooks - 表格 */
|
||||
const gridOptions2 = reactive(gridProps({
|
||||
columns: [
|
||||
{ type: 'seq', title: '序号', width: 60 },
|
||||
{ field: 'phaseName', title: '标段名称', width: 150, editRender: { name: 'input' } },
|
||||
{ field: 'phaseMoney', title: '预算金额(人民币元)', width: 200, editRender: { name: 'input', attrs: { type: 'number' } } },
|
||||
{ field: 'phaseDesc', title: '范围说明', minWidth: 120, editRender: { name: 'input' } },
|
||||
],
|
||||
data: [],
|
||||
toolbarConfig: {
|
||||
enabled: false
|
||||
},
|
||||
pagerConfig: {
|
||||
enabled: false
|
||||
},
|
||||
editConfig: {
|
||||
trigger: 'click',
|
||||
mode: 'row'
|
||||
},
|
||||
}));
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
|
@ -174,6 +218,24 @@ async function handleOpenChooseBasisContractModal(status: boolean) {
|
|||
}
|
||||
|
||||
|
||||
/** 标段选择回调 */
|
||||
function handleBidChange(e) {
|
||||
console.log('[ handleBidChange ] >', e)
|
||||
let arr = new Array<number>(e).fill(0);
|
||||
let data: any[] = [];
|
||||
console.log('[ arr ] >', arr)
|
||||
arr.forEach(element => {
|
||||
|
||||
data.push({
|
||||
phaseName: '',
|
||||
phaseMoney: '',
|
||||
phaseDesc: ''
|
||||
})
|
||||
});
|
||||
console.log('[ data ] >', data)
|
||||
xGridRef2.value?.loadData(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 筛选合同列表数据
|
||||
*
|
||||
|
@ -186,18 +248,116 @@ function filterContractTypes(parentId: string) {
|
|||
}).filter((item) => item.parentId === parentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存
|
||||
*/
|
||||
async function handleSave(type: "submit" | "upload") {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
console.log('[ currData.value ] >', currData.value)
|
||||
|
||||
let info = JSON.parse(JSON.stringify(currData.value))
|
||||
|
||||
// 项目名称
|
||||
info.projectName = getDictObj(DICT_TYPE.comprehensiveProjectName, info.projectNameId)
|
||||
// 商务计价方式
|
||||
info.priceStyleName = getDictObj(DICT_TYPE.contractPriceStyle, info.priceStyleId)
|
||||
// 选商方式
|
||||
info.choiceTypeName = getDictObj(DICT_TYPE.contractSelectionMethod, info.choiceType)
|
||||
|
||||
|
||||
let form = {
|
||||
contractBaseInfo: contractData.value,
|
||||
selectMerchantsBasicInfo: info,
|
||||
biddingList: xGridRef2.value?.getTableData().fullData
|
||||
}
|
||||
|
||||
if (form.selectMerchantsBasicInfo.isBid) {
|
||||
let biddingList: any[] = xGridRef2.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
|
||||
}
|
||||
|
||||
|
||||
resolve(true)
|
||||
|
||||
})
|
||||
|
||||
|
||||
console.log('[ form ] >', form)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交
|
||||
*/
|
||||
async function handleSubmit(type: "submit" | "upload") {
|
||||
|
||||
|
||||
// 先保存再提交
|
||||
dialog.warning({
|
||||
title: "提示",
|
||||
content: `提交前需要先保存记录,保存后将自动进行提交,是否确认保存?`,
|
||||
positiveText: "确认",
|
||||
negativeText: "取消",
|
||||
onPositiveClick: async () => {
|
||||
await handleSave("upload")
|
||||
},
|
||||
});
|
||||
|
||||
return
|
||||
console.log('[ currData.value ] >', currData.value)
|
||||
|
||||
let form = {
|
||||
contractBaseInfo: contractData.value,
|
||||
selectMerchantsBasicInfo: currData.value,
|
||||
biddingList: biddingList.value
|
||||
biddingList: xGridRef2.value?.getTableData().fullData
|
||||
}
|
||||
|
||||
if (form.selectMerchantsBasicInfo.isBid) {
|
||||
let biddingList: any[] = xGridRef2.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
|
||||
}
|
||||
|
||||
console.log('[ form ] >', form)
|
||||
|
||||
return
|
||||
if (type === "submit") {
|
||||
// 提交
|
||||
|
@ -286,11 +446,11 @@ function handleBack() {
|
|||
<div>
|
||||
<n-affix class="z-20 w-full bg-white py-1" :trigger-top="10" position="absolute" :listen-to="() => containerRef">
|
||||
<n-space>
|
||||
<!-- <n-button type="primary" size="small" @click="handleSubmit('upload')">
|
||||
<n-button type="primary" size="small" @click="handleSave('upload')">
|
||||
<template #icon>
|
||||
<icon-mdi-content-save-outline />
|
||||
</template>
|
||||
保存</n-button> -->
|
||||
保存</n-button>
|
||||
|
||||
<n-button type="primary" size="small" @click="handleSubmit('upload')">
|
||||
<template #icon>
|
||||
|
@ -330,7 +490,7 @@ function handleBack() {
|
|||
<n-descriptions-item :span="6">
|
||||
<template #label>
|
||||
合同名称
|
||||
<span v-if="isRequired('contractName')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('contractName')" class="text-red">*</span>
|
||||
</template>
|
||||
<n-input v-model:value="contractData.contractName" placeholder="请输入"></n-input>
|
||||
</n-descriptions-item>
|
||||
|
@ -338,37 +498,31 @@ function handleBack() {
|
|||
<n-descriptions-item :span="3">
|
||||
<template #label>
|
||||
合同类别
|
||||
<span v-if="isRequired('ctrType')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('ctrType')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="">
|
||||
<NSelect v-model:value="contractData.ctrType" :options="filterContractTypes('-1')" placeholder="请选择合同类别"
|
||||
@update:value="() => contractData.ctrTwoType = null">
|
||||
<NSelect v-model:value="contractData.ctrType" class="w-400px" :options="filterContractTypes('-1')"
|
||||
placeholder="请选择合同类别" @update:value="() => contractData.ctrTwoType = null">
|
||||
</NSelect>
|
||||
<!-- <DictTag v-model:value="contractData.ctrType" :options="filterContractTypes('-1')" selectable>
|
||||
</DictTag> -->
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
<n-descriptions-item :span="3">
|
||||
<template #label>
|
||||
二级类别
|
||||
<span v-if="isRequired('ctrTwoType')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('ctrTwoType')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="">
|
||||
<NSelect v-model:value="contractData.ctrTwoType" :options="filterContractTypes(contractData.ctrType)"
|
||||
placeholder="请选择二级类别">
|
||||
</NSelect>
|
||||
|
||||
<!-- <DictTag v-model:value="contractData.ctrTwoType" :options="filterContractTypes(contractData.ctrType)"
|
||||
selectable placeholder="请选择二级类别">
|
||||
</DictTag> -->
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
<n-descriptions-item :span="6">
|
||||
<template #label>
|
||||
资金流向
|
||||
<span v-if="isRequired('fundAllocation')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('fundAllocation')" class="text-red">*</span>
|
||||
</template>
|
||||
<DictTag v-model:value="contractData.fundAllocation" :options="getDictOptions(DICT_TYPE.contractFundFlow)"
|
||||
selectable> </DictTag>
|
||||
|
@ -377,7 +531,7 @@ function handleBack() {
|
|||
<n-descriptions-item :span="6">
|
||||
<template #label>
|
||||
资金渠道
|
||||
<span v-if="isRequired('fundDitch')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('fundDitch')" class="text-red">*</span>
|
||||
</template>
|
||||
<DictTag v-model:value="contractData.fundDitch" :options="getDictOptions(DICT_TYPE.contractFundingSource)"
|
||||
selectable> </DictTag>
|
||||
|
@ -386,7 +540,7 @@ function handleBack() {
|
|||
<n-descriptions-item :span="6">
|
||||
<template #label>
|
||||
组织形式
|
||||
<span v-if="isRequired('organiza')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('organiza')" class="text-red">*</span>
|
||||
</template>
|
||||
<div>
|
||||
<DictTag v-model:value="contractData.organiza"
|
||||
|
@ -397,7 +551,7 @@ function handleBack() {
|
|||
<n-descriptions-item :span="2">
|
||||
<template #label>
|
||||
预算金额
|
||||
<span v-if="isRequired('budgetSum')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('budgetSum')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="flex flex-row">
|
||||
<n-input-number class="flex-1" v-model:value="contractData.budgetSum"
|
||||
|
@ -409,7 +563,7 @@ function handleBack() {
|
|||
|
||||
<n-descriptions-item :span="2">
|
||||
<template #label> 框架协议 </template>
|
||||
<span v-if="isRequired('frameProtocol')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('frameProtocol')" class="text-red">*</span>
|
||||
<n-radio-group v-model:value="contractData.frameProtocol" name="radiogroup1">
|
||||
<n-space>
|
||||
<n-radio :value="1"> 是 </n-radio>
|
||||
|
@ -420,7 +574,7 @@ function handleBack() {
|
|||
|
||||
<n-descriptions-item :span="2" label-width="150px">
|
||||
<template #label> 框架协议下的合同 </template>
|
||||
<span v-if="isRequired('frameProtocolCtr')" class="text-red">*</span>
|
||||
<span v-if="isRequiredByContractBase('frameProtocolCtr')" class="text-red">*</span>
|
||||
<n-radio-group v-model:value="contractData.frameProtocolCtr" name="radiogroup2">
|
||||
<n-space>
|
||||
<n-radio :value="1"> 是 </n-radio>
|
||||
|
@ -485,10 +639,10 @@ function handleBack() {
|
|||
|
||||
<n-descriptions-item :span="3">
|
||||
<template #label> 选商方式
|
||||
<span v-if="isRequired('priceStyleId')" class="text-red">*</span>
|
||||
<span v-if="isRequired('choiceType')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="">
|
||||
<DictTag v-model:value="currData.priceStyleId"
|
||||
<DictTag v-model:value="currData.choiceType"
|
||||
:options="getDictOptions(DICT_TYPE.contractSelectionMethod)" selectable> </DictTag>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
@ -523,7 +677,9 @@ function handleBack() {
|
|||
<div class="mx-12"></div>
|
||||
<div v-if="currData.isBid" class="flex flex-row mr-6 flex-1 items-center">
|
||||
<div class="w-80px">标段数:</div>
|
||||
<NSelect class="mr-2" :options="bidList"></NSelect>
|
||||
<NSelect v-model:value="currData.bidNum" class="mr-2" :options="bidList"
|
||||
@update:value="handleBidChange">
|
||||
</NSelect>
|
||||
</div>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
@ -533,9 +689,8 @@ function handleBack() {
|
|||
<template #label> 标段信息
|
||||
<span v-if="isRequired('isBid')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="">
|
||||
<DictTag v-model:value="currData.isBid" :options="getDictOptions(DICT_TYPE.sectionType)" selectable>
|
||||
</DictTag>
|
||||
<div class="h-300px">
|
||||
<vxe-grid ref="xGridRef2" v-bind="gridOptions2"></vxe-grid>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
|
@ -585,21 +740,8 @@ function handleBack() {
|
|||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
</n-descriptions>
|
||||
</n-spin>
|
||||
</n-card>
|
||||
|
||||
<n-card size="small">
|
||||
<template #header>
|
||||
<div class="flex flex-row items-center">
|
||||
<span>招标文件</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<n-spin :show="loading || addressLoading">
|
||||
<n-descriptions label-placement="left" bordered :column="3" label-class="w-100px" size="small">
|
||||
<n-descriptions-item :span="3">
|
||||
<template #label> 相关附件 </template>
|
||||
<template #label> 招标文件 </template>
|
||||
<div>
|
||||
<NUpload ref="uploadAfterRef" directory-dnd multiple :file-list="fileUploader.fileList.value"
|
||||
:custom-request="fileUploader.customRequest" show-download-button :default-upload="false" :max="5"
|
||||
|
@ -609,6 +751,7 @@ function handleBack() {
|
|||
</NUpload>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
</n-descriptions>
|
||||
</n-spin>
|
||||
</n-card>
|
||||
|
|
|
@ -385,7 +385,7 @@ function handleBack() {
|
|||
<NDescriptionsItem label="承办人">{{ currData.inputPerson }}</NDescriptionsItem>
|
||||
<NDescriptionsItem label="承办人部门">{{
|
||||
currData.inputDepartName
|
||||
}}</NDescriptionsItem>
|
||||
}}</NDescriptionsItem>
|
||||
<NDescriptionsItem label="承办时间">{{ currData.inputDate }}</NDescriptionsItem>
|
||||
</NDescriptions>
|
||||
</NCard>
|
||||
|
@ -533,7 +533,11 @@ function handleBack() {
|
|||
<span v-if="isRequired('zxh')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="flex flex-row items-center">
|
||||
<n-input-number v-model:value="currData2.zxh" placeholder="请输入" />个月
|
||||
<n-input-number v-model:value="currData2.zxh" placeholder="请输入">
|
||||
<template #suffix>
|
||||
个月
|
||||
</template>
|
||||
</n-input-number>
|
||||
</div>
|
||||
</NDescriptionsItem>
|
||||
|
||||
|
@ -543,7 +547,11 @@ function handleBack() {
|
|||
<span v-if="isRequired('yfklb')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="flex flex-row items-center">
|
||||
<n-input-number v-model:value="currData2.yfklb" placeholder="请输入" />%
|
||||
<n-input-number v-model:value="currData2.yfklb" placeholder="请输入">
|
||||
<template #suffix>
|
||||
%
|
||||
</template>
|
||||
</n-input-number>
|
||||
</div>
|
||||
</NDescriptionsItem>
|
||||
|
||||
|
@ -553,7 +561,11 @@ function handleBack() {
|
|||
<span v-if="isRequired('bzjbl')" class="text-red">*</span>
|
||||
</template>
|
||||
<div class="flex flex-row items-center">
|
||||
<n-input-number v-model:value="currData2.bzjbl" placeholder="请输入" />%
|
||||
<n-input-number v-model:value="currData2.bzjbl" placeholder="请输入">
|
||||
<template #suffix>
|
||||
%
|
||||
</template>
|
||||
</n-input-number>
|
||||
</div>
|
||||
</NDescriptionsItem>
|
||||
|
||||
|
@ -593,6 +605,18 @@ function handleBack() {
|
|||
<n-input v-model:value="currData2.cbryj" type="textarea" placeholder="请输入" />
|
||||
</NDescriptionsItem>
|
||||
|
||||
<n-descriptions-item :span="3">
|
||||
<template #label> 合同相关资料 </template>
|
||||
<div>
|
||||
<NUpload ref="uploadRef" directory-dnd multiple :file-list="fileUploader.fileList.value"
|
||||
:custom-request="fileUploader.customRequest" show-download-button :default-upload="false" :max="5"
|
||||
@update:file-list="fileUploader.handleFileUpdate" @download="handleDownload"
|
||||
@finish="fileUploader.handleFileUploadFinish">
|
||||
<n-button>上传文件</n-button>
|
||||
</NUpload>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
</NDescriptions>
|
||||
</NCard>
|
||||
|
||||
|
@ -629,29 +653,6 @@ function handleBack() {
|
|||
</n-spin>
|
||||
</n-card>
|
||||
|
||||
<n-card size="small">
|
||||
<template #header>
|
||||
<div class="flex flex-row items-center">
|
||||
<span>合同相关资料</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<n-spin :show="loading || addressLoading">
|
||||
<n-descriptions label-placement="left" bordered :column="3" label-class="w-100px" size="small">
|
||||
<n-descriptions-item :span="3">
|
||||
<template #label> 相关附件 </template>
|
||||
<div>
|
||||
<NUpload ref="uploadRef" directory-dnd multiple :file-list="fileUploader.fileList.value"
|
||||
:custom-request="fileUploader.customRequest" show-download-button :default-upload="false" :max="5"
|
||||
@update:file-list="fileUploader.handleFileUpdate" @download="handleDownload"
|
||||
@finish="fileUploader.handleFileUploadFinish">
|
||||
<n-button>上传文件</n-button>
|
||||
</NUpload>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-spin>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -7,6 +7,10 @@ import LineChart from './modules/line-chart.vue';
|
|||
import PieChart from './modules/pie-chart.vue';
|
||||
import ProjectNews from './modules/project-news.vue';
|
||||
import CreativityBanner from './modules/creativity-banner.vue';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
|
||||
const { routerPushByKey } = useRouterPush();
|
||||
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
|
@ -16,8 +20,8 @@ const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
|||
<template>
|
||||
<NSpace vertical :size="16">
|
||||
<HeaderBanner />
|
||||
<CardData />
|
||||
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||
<!-- <CardData /> -->
|
||||
<!-- <NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||
<NGi span="24 s:24 m:14">
|
||||
<NCard :bordered="false" class="card-wrapper">
|
||||
<LineChart />
|
||||
|
@ -28,16 +32,92 @@ const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
|||
<PieChart />
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||
<NGi span="24 s:24 m:14">
|
||||
<ProjectNews />
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:10">
|
||||
<CreativityBanner />
|
||||
</NGrid> -->
|
||||
|
||||
<NGrid class="" cols="1" responsive="screen" :x-gap="12" :y-gap="9">
|
||||
<NGi>
|
||||
<NCard :segmented="{ content: true }" content-style="padding: 0;" :bordered="false" size="small" title="快捷操作">
|
||||
<div class="flex flex-wrap project-card">
|
||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable
|
||||
@click="routerPushByKey('canteen_orderfood')">
|
||||
<div class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" color="#fab251">
|
||||
<span class="i-icon-park-outline:cooking" />
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">订餐</span>
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable
|
||||
@click="routerPushByKey('bussiness-trip')">
|
||||
<div class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" color="#68c755">
|
||||
<span class="i-icon-park-outline:train" />
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">出差查询</span>
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable
|
||||
@click="routerPushByKey('meeting_home')">
|
||||
<div class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" color="#1890ff">
|
||||
<span class="i-icon-park-outline:online-meeting" />
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">会议查询</span>
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable
|
||||
@click="routerPushByKey('office-supplies_apply')">
|
||||
<div class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" color="#f06b96">
|
||||
<span class="i-icon-park-outline:editor" />
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">办公用品申请</span>
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable @click="routerPushByKey('duty')">
|
||||
<div class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" color="#7238d1">
|
||||
<span class="i-icon-park-outline:worker" />
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">值班管理</span>
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable
|
||||
@click="routerPushByKey('supervise_list')">
|
||||
<div class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" color="">
|
||||
<span class="i-icon-park-outline:list-view" />
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">立项查询</span>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.project-card {
|
||||
margin-right: -6px;
|
||||
}
|
||||
|
||||
.project-card-item {
|
||||
margin: -1px;
|
||||
width: 33.333333%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -50,13 +50,13 @@ const statisticData = computed<StatisticData[]>(() => [
|
|||
<h3 class="text-18px font-semibold">
|
||||
{{ $t('page.home.greeting', { userName: authStore.userInfo.userName }) }}
|
||||
</h3>
|
||||
<p class="text-#999 leading-30px">{{ $t('page.home.weatherDesc') }}</p>
|
||||
<!-- <p class="text-#999 leading-30px">{{ $t('page.home.weatherDesc') }}</p> -->
|
||||
</div>
|
||||
</div>
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:6">
|
||||
<NSpace :size="24" justify="end">
|
||||
<NStatistic v-for="item in statisticData" :key="item.id" class="whitespace-nowrap" v-bind="item" />
|
||||
<!-- <NStatistic v-for="item in statisticData" :key="item.id" class="whitespace-nowrap" v-bind="item" /> -->
|
||||
</NSpace>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
|
Loading…
Reference in New Issue