Commit f267cff7999d05e481ae22a9c1aa3aa7641c38f6

Authored by boyang
1 parent cbe36709

feat: 历史记录

src/api/project/approve.ts
... ... @@ -21,12 +21,11 @@ export const approveAuditApi = async (params: any) =>
21 21 { message: '操作成功' },
22 22 );
23 23  
24   -export const getWaitListApi = async (params: DemoParams) => {
  24 +export const getWaitListApi = async (params: any) => {
25 25 const res = await defHttp.post({
26 26 url: Api.APPROVE,
27 27 params,
28 28 });
29   -
30 29 res.records = res.records.map((item) => {
31 30 return item;
32 31 });
... ... @@ -44,7 +43,7 @@ export const getApprovedListApi = async (params: any) => {
44 43 res.records = res.records.map((item) => {
45 44 return item;
46 45 });
47   -
  46 + console.log(res, '56567ressss');
48 47 return new Promise((resolve) => {
49 48 resolve({ items: res.records, total: res.total });
50 49 });
... ...
src/api/project/invoice.ts
... ... @@ -50,6 +50,12 @@ enum Api {
50 50 SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请修改
51 51 APPLYLIST = '/project/pageProjectLockFieldApply', //分页查询项目字段申请记录
52 52 AUDITAPPLY = '/project/audit', //审核
  53 + ACTIONRECORD = '/projectOptLog/listByPage', //业务/内部研发净利润操作记录以及申请记录
  54 + ORDERCOSTDETAILEDOPTLOG = '/orderCostDetailedOptLog/listByPage', //包装费用明细/内部生产明细操作记录表
  55 + ORDERCOSTDETAILEDEXPORT = '/project/businessProfit/exportExcel', //业务研发净利润分析表导出
  56 + INNERPRODUCEPROFITEXPORT = '/project/innerProfitInfo/exportExcel', //内部生产净利润分析表导出
  57 + BUSINESSPROFITDETAIL = '/order/cost/businessProfitDetail/exportExcel', //包装费用明细导出
  58 + INNERPROFITDETAIL = '/order/cost/innerProfitDetail/exportExcel', //内部生产明细导出
53 59 }
54 60  
55 61 export const getRefundDate = async (params: any, data?: any) => {
... ... @@ -427,18 +433,30 @@ export const getServiceApplyEdit = async (params: any) => {
427 433 };
428 434  
429 435 export const getApplyList = async (params: any) => {
430   - const res = ref();
431   - res.value = await defHttp.post<any>({
  436 + // const res = ref();
  437 + // res.value = await defHttp.post<any>({
  438 + // url: Api.APPLYLIST,
  439 + // params,
  440 + // });
  441 + // res.value.data.records.forEach((record) => {
  442 + // const jsonObj = JSON.parse(record?.fields);
  443 + // if (jsonObj) {
  444 + // record.fields = jsonObj;
  445 + // }
  446 + // });
  447 + // return res.value.data.records;
  448 + const data = await defHttp.post({
432 449 url: Api.APPLYLIST,
433 450 params,
434 451 });
435   - res.value.data.records.forEach((record) => {
436   - const jsonObj = JSON.parse(record?.fields);
437   - if (jsonObj) {
438   - record.fields = jsonObj;
439   - }
  452 + const res = data.data;
  453 + res.records = res.records.map((item) => {
  454 + return item;
  455 + });
  456 +
  457 + return new Promise((resolve) => {
  458 + resolve({ items: res.records, total: res.total });
440 459 });
441   - return res.value.data.records;
442 460 };
443 461  
444 462 export const getAuditApply = async (params: any) => {
... ... @@ -461,3 +479,70 @@ export const checkDeleteDeduct = async (params: any) =&gt; {
461 479 params,
462 480 });
463 481 };
  482 +
  483 +export const getProjectOptLog = async (params: any) => {
  484 + const res = await defHttp.post<any>({
  485 + url: Api.ACTIONRECORD,
  486 + params,
  487 + });
  488 + const formattedRecords = res.records.map((record: any) => {
  489 + return {
  490 + ...record,
  491 + };
  492 + });
  493 + const orderStore = useOrderStoreWithOut();
  494 + orderStore.setTotal(res.total);
  495 + orderStore.setQueryVO(params);
  496 + return new Promise((resolve) => {
  497 + resolve({
  498 + items: formattedRecords,
  499 + total: res.total,
  500 + });
  501 + });
  502 +};
  503 +
  504 +export const getOrderCostDetailedOptLog = async (params: any) => {
  505 + const res = await defHttp.post<any>({
  506 + url: Api.ORDERCOSTDETAILEDOPTLOG,
  507 + params,
  508 + });
  509 + const formattedRecords = res.records.map((record: any) => {
  510 + return {
  511 + ...record,
  512 + };
  513 + });
  514 + const orderStore = useOrderStoreWithOut();
  515 + orderStore.setTotal(res.total);
  516 + orderStore.setQueryVO(params);
  517 + return new Promise((resolve) => {
  518 + resolve({
  519 + items: formattedRecords,
  520 + total: res.total,
  521 + });
  522 + });
  523 +};
  524 +export const getBusinessProfitExport = async (params: any) => {
  525 + return await defHttp.post<any>({
  526 + url: Api.ORDERCOSTDETAILEDEXPORT,
  527 + params,
  528 + });
  529 +};
  530 +
  531 +export const getInnerProfitInfoExport = async (params: any) => {
  532 + return await defHttp.post<any>({
  533 + url: Api.INNERPRODUCEPROFITEXPORT,
  534 + params,
  535 + });
  536 +};
  537 +export const getBusinessProfitDetailExport = async (params: any) => {
  538 + return await defHttp.post<any>({
  539 + url: Api.BUSINESSPROFITDETAIL,
  540 + params,
  541 + });
  542 +};
  543 +export const getInnerProfitDetail = async (params: any) => {
  544 + return await defHttp.post<any>({
  545 + url: Api.INNERPROFITDETAIL,
  546 + params,
  547 + });
  548 +};
464 549 \ No newline at end of file
... ...
src/router/routes/modules/project/finance.ts
... ... @@ -116,8 +116,8 @@ const finance: AppRouteModule = {
116 116 },
117 117 children: [
118 118 {
119   - path: 'InnerData',
120   - name: 'InnerData',
  119 + path: 'InnerProduce',
  120 + name: 'InnerProduce',
121 121 meta: {
122 122 title: '内部生产净利润分析表',
123 123 roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
... ... @@ -129,8 +129,8 @@ const finance: AppRouteModule = {
129 129 ),
130 130 },
131 131 {
132   - path: 'InnerProduce',
133   - name: 'InnerProduce',
  132 + path: 'InnerData',
  133 + name: 'InnerData',
134 134 meta: {
135 135 title: '内部生产明细表',
136 136 roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
... ...
src/views/project/finance/financeProfit/ProductProfit/InnerData/FinanceEdit.vue
... ... @@ -32,6 +32,14 @@
32 32 auto-size
33 33 />
34 34 <div style="margin: 16px 0"></div>
  35 + <div style="font-size: 15px">生产科预算单价</div>
  36 + <a-input
  37 + v-model:value="input3"
  38 + placeholder="请输入"
  39 + :disabled="status3 == 'LOCKED'"
  40 + auto-size
  41 + />
  42 + <div style="margin: 16px 0"></div>
35 43  
36 44 <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
37 45 <template #appendFooter>
... ... @@ -126,20 +134,26 @@
126 134 const update = ref();
127 135 const status1 = ref();
128 136 const status2 = ref();
  137 + const status3 = ref();
129 138  
130 139 const input1 = ref();
131 140 const input2 = ref();
  141 + const input3 = ref();
  142 + const orderCount = ref();
132 143 const id = ref();
133 144 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => {
134 145 // 方式1
135 146 if (data.data?.lockFields) {
136 147 status1.value = data.data?.lockFields?.productionDepartmentPredictPrice;
137 148 status2.value = data.data?.lockFields?.productionActualPrice;
  149 + status3.value = data.data?.lockFields?.productionDepartmentPredictUnitprice;
138 150 }
139 151  
140 152 id.value = data.data.orderId;
141 153 input1.value = data.data?.productionDepartmentPredictPrice.toFixed(2);
142 154 input2.value = data.data?.productionActualPrice.toFixed(2);
  155 + orderCount.value = data.data?.orderCount;
  156 + input3.value = data.data?.productionDepartmentPredictUnitprice.toFixed(2);
143 157 resetFields();
144 158 setDrawerProps({ confirmLoading: false });
145 159 // setFieldsValue({
... ... @@ -155,13 +169,15 @@
155 169 // id: update.value.data.id,
156 170 // bgUrl: update.value.data.bgUrl,
157 171 // };
158   - if (!input1.value || !input2.value) {
  172 + if (!input1.value || !input2.value || !input3.value) {
159 173 error('选项不能为空');
160 174 } else {
161 175 await getPackageEdit({
162 176 orderId: id.value,
163 177 productionDepartmentPredictPrice: input1.value,
164 178 productionActualPrice: input2.value,
  179 + orderCount: orderCount.value,
  180 + productionDepartmentPredictUnitprice: input3.value,
165 181 });
166 182 emit('success');
167 183 closeDrawer();
... ... @@ -171,6 +187,7 @@
171 187 if (!visible) {
172 188 input1.value = '';
173 189 input2.value = '';
  190 + input3.value = '';
174 191 }
175 192 }
176 193 </script>
... ...
src/views/project/finance/financeProfit/ProductProfit/InnerData/HistoryDetail.vue 0 → 100644
  1 +<template>
  2 + <BasicDrawer
  3 + @register="register"
  4 + v-bind="$attrs"
  5 + title="操作记录"
  6 + width="60%"
  7 + :isDetail="true"
  8 + :showDetailBack="false"
  9 + okText="保存"
  10 + :destroyOnClose="true"
  11 + >
  12 + <Tabs v-model:activeKey="activeKey" className="my-0">
  13 + <TabPanel :key="1" tab="操作记录" className="w-full">
  14 + <a-list :pagination="pagination1" className="w-full">
  15 + <template v-for="item in list1" :key="item.id">
  16 + <a-list-item class="list">
  17 + <a-list-item-meta>
  18 + <template #avatar> </template>
  19 + <template #title>
  20 + <span>{{ item.userName }}</span>
  21 + </template>
  22 + <template #description>
  23 + <div class="description">
  24 + {{ item.optType }}
  25 + </div>
  26 + <div class="info">
  27 + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div>
  28 + </div>
  29 + </template>
  30 + </a-list-item-meta>
  31 + </a-list-item>
  32 + </template>
  33 + </a-list>
  34 + </TabPanel>
  35 + <TabPanel :key="2" tab="审批记录" className="w-full">
  36 + <a-list :pagination="pagination2" className="w-full">
  37 + <template v-for="item in list2" :key="item.id">
  38 + <a-list-item class="list">
  39 + <a-list-item-meta>
  40 + <template #avatar> </template>
  41 + <template #title>
  42 + <span>{{ item.userName }}</span>
  43 + </template>
  44 + <template #description>
  45 + <div class="description">
  46 + {{ item.optType }}
  47 + </div>
  48 + <div class="info">
  49 + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div>
  50 + </div>
  51 + </template>
  52 + </a-list-item-meta>
  53 + </a-list-item>
  54 + </template>
  55 + </a-list>
  56 + </TabPanel>
  57 + </Tabs>
  58 +
  59 + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
  60 + <template #appendFooter>
  61 + <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> -->
  62 + </template>
  63 + </BasicDrawer>
  64 +</template>
  65 +<script lang="ts">
  66 + import { defineComponent, ref, computed } from 'vue';
  67 + import { Tabs, List } from 'ant-design-vue';
  68 + import { FormSchema } from '/@/components/Form/index';
  69 +
  70 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  71 + import { getOrderCostDetailedOptLog } from '/@/api/project/invoice';
  72 + import { formatToDateTime } from '/@/utils/dateUtil';
  73 +
  74 + const TabPanel = Tabs.TabPane;
  75 +
  76 + const schemas: FormSchema[] = [
  77 + {
  78 + field: '订单号',
  79 + component: 'Input',
  80 + label: '字段1',
  81 + componentProps: {
  82 + readonly: true,
  83 + disabled: true,
  84 + },
  85 + colProps: {
  86 + span: 12,
  87 + },
  88 + defaultValue: '111',
  89 + },
  90 + {
  91 + field: 'field2',
  92 + component: 'Input',
  93 + label: '字段2',
  94 + colProps: {
  95 + span: 12,
  96 + },
  97 + },
  98 + ];
  99 + const achieveList = [
  100 + {
  101 + key: '1',
  102 + name: '操作记录',
  103 + },
  104 + {
  105 + key: '2',
  106 + name: '审批记录',
  107 + },
  108 + ];
  109 + export default defineComponent({
  110 + components: {
  111 + BasicDrawer,
  112 + Tabs,
  113 + TabPanel,
  114 + [List.name]: List,
  115 + [List.Item.name]: List.Item,
  116 + AListItemMeta: List.Item.Meta,
  117 + },
  118 + props: {
  119 + onGoCheckDetail: {
  120 + type: Function,
  121 + },
  122 + },
  123 + setup() {
  124 + const list1 = ref([]);
  125 + const total1 = ref(0);
  126 + const page1 = ref(1);
  127 +
  128 + const list2 = ref([]);
  129 + const total2 = ref(0);
  130 + const page2 = ref(1);
  131 + const orderId = ref('');
  132 + const activeKey = ref(1);
  133 +
  134 + const getOrderOptLogFunc = async (data, index, page) => {
  135 + console.log('%c [ data ]-135', 'font-size:13px; background:pink; color:#bf2c9f;', data);
  136 + if (index === 1) {
  137 + const res = await getOrderCostDetailedOptLog({
  138 + orderId: data,
  139 + type: 40,
  140 + page: page,
  141 + pageSize: 20,
  142 + });
  143 + list1.value = res.items;
  144 + total1.value = res.total;
  145 + page1.value = page;
  146 + } else {
  147 + const res = await getOrderCostDetailedOptLog({
  148 + orderId: data,
  149 + type: 70,
  150 + page: page,
  151 + pageSize: 20,
  152 + });
  153 + list2.value = res.items;
  154 + total2.value = res.total;
  155 + page2.value = page;
  156 + }
  157 + };
  158 + const [register] = useDrawerInner((data) => {
  159 + orderId.value = data.data.orderId;
  160 + getOrderOptLogFunc(orderId.value, 1, 1);
  161 + getOrderOptLogFunc(orderId.value, 2, 1);
  162 + });
  163 +
  164 + const pagination1 = computed(() => {
  165 + return {
  166 + show: true,
  167 + pageSize: 20,
  168 + page: page1.value,
  169 + total: total1.value,
  170 + onChange(cur) {
  171 + getOrderOptLogFunc(orderId.value, 1, cur);
  172 + },
  173 + };
  174 + });
  175 +
  176 + const pagination2 = computed(() => {
  177 + return {
  178 + show: true,
  179 + pageSize: 20,
  180 + page: page1.value,
  181 + total: total1.value,
  182 + onChange(cur) {
  183 + getOrderOptLogFunc(orderId.value, 2, cur);
  184 + },
  185 + };
  186 + });
  187 +
  188 + return {
  189 + register,
  190 + schemas,
  191 + achieveList,
  192 + list1,
  193 + list2,
  194 + prefixCls: 'account-center',
  195 + pagination1,
  196 + pagination2,
  197 + activeKey,
  198 + formatToDateTime,
  199 + };
  200 + },
  201 + });
  202 +</script>
... ...
src/views/project/finance/financeProfit/ProductProfit/InnerData/data.tsx
... ... @@ -137,7 +137,15 @@ export const COLUMNS = [
137 137 },
138 138 },
139 139 {
140   - title: '生产科预算金额¥',
  140 + title: '生产科预算单价¥',
  141 + width: 150,
  142 + dataIndex: 'productionDepartmentPredictUnitprice',
  143 + customRender: (column) => {
  144 + return column.record?.productionDepartmentPredictUnitprice?.toFixed(2);
  145 + },
  146 + },
  147 + {
  148 + title: '生产科预算总金额¥',
141 149 width: 150,
142 150 dataIndex: 'productionDepartmentPredictPrice',
143 151 customRender: (column) => {
... ... @@ -145,9 +153,9 @@ export const COLUMNS = [
145 153 },
146 154 },
147 155 {
148   - title: '实际发生费用',
  156 + title: '生产科实际花费总金额¥',
149 157 dataIndex: 'productionActualPrice',
150   - width: 120,
  158 + width: 180,
151 159 customRender: (column) => {
152 160 return column.record?.productionActualPrice?.toFixed(2);
153 161 },
... ... @@ -212,6 +220,20 @@ export const COLUMNS = [
212 220 return column.record?.grossProfitRate?.toFixed(2);
213 221 },
214 222 },
  223 + {
  224 + title: '状态',
  225 + dataIndex: 'status',
  226 + width: 120,
  227 + customRender: (column) => {
  228 + if (column.record?.status === '-1') {
  229 + return '未完成';
  230 + } else if (column.record?.status === '0') {
  231 + return '待审核';
  232 + } else if (column.record?.status === '1') {
  233 + return '已审核';
  234 + }
  235 + },
  236 + },
215 237 // {
216 238 // title: '内部生产固定成本¥',
217 239 // dataIndex: 'innerProductionFixedCost',
... ...
src/views/project/finance/financeProfit/ProductProfit/InnerData/index.vue
... ... @@ -6,7 +6,7 @@
6 6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 7 </template>
8 8 <template v-if="column.key === 'action'">
9   - <TableAction :actions="createActions(record)" />
  9 + <TableAction :actions="createActions(record)" :dropDownActions="createDropActions(record)" />
10 10 </template>
11 11 <!-- <template v-if="column.key === 'relationValue'">
12 12 <a-input
... ... @@ -32,8 +32,9 @@
32 32 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" />
33 33 </div>
34 34 </BasicModal> -->
35   - <CheckDetail @register="checkModalRegister" />
  35 + <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
36 36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  37 + <HistoryDetail @register="registerHistoryDetail" />
37 38 </div>
38 39 </template>
39 40 <script setup lang="ts">
... ... @@ -42,11 +43,15 @@
42 43 import { searchFormSchema, COLUMNS } from './data';
43 44 import { BasicModal, useModal } from '/@/components/Modal';
44 45 import { useMessage } from '/@/hooks/web/useMessage';
45   - import { onMounted, ref } from 'vue';
  46 + import { onMounted, ref, computed } from 'vue';
46 47 import { useDrawer } from '/@/components/Drawer';
47 48 import FinanceEdit from './FinanceEdit.vue';
48 49 import CheckDetail from './CheckDetail.vue';
  50 + import HistoryDetail from './HistoryDetail.vue';
49 51 import { useOrderStoreWithOut } from '/@/store/modules/order';
  52 + import { useUserStoreWithOut } from '/@/store/modules/user';
  53 + import { RoleEnum } from '/@/enums/roleEnum';
  54 + import { ROLE } from '../../../type.d';
50 55  
51 56 const { createMessage } = useMessage();
52 57 const { error } = createMessage;
... ... @@ -54,6 +59,12 @@
54 59 const orderStore = useOrderStoreWithOut();
55 60 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
56 61 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer();
  62 + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer();
  63 + const userStore = useUserStoreWithOut();
  64 + const user = userStore.getUserInfo;
  65 + const role = computed(() => {
  66 + return user?.roleSmallVO?.code;
  67 + });
57 68 const handleOk = (record) => {
58 69 // 修改父组件的状态
59 70 closeModal();
... ... @@ -80,7 +91,7 @@
80 91 setting: false,
81 92 },
82 93 actionColumn: {
83   - width: 240,
  94 + width: 260,
84 95 title: 'Action',
85 96 dataIndex: 'action',
86 97 },
... ... @@ -111,6 +122,18 @@
111 122 // },
112 123 onClick: handleFalse.bind(null, record),
113 124 },
  125 + {
  126 + label: '审批通过',
  127 + popConfirm: {
  128 + title: '确认审批?',
  129 + confirm: () => {
  130 + if (record.status === 0 && role.value === ROLE.ADMIN) {
  131 + handleStatus(record, true);
  132 + }
  133 + return;
  134 + },
  135 + },
  136 + },
114 137 ];
115 138 }
116 139 return [
... ... @@ -128,6 +151,18 @@
128 151 ];
129 152 }
130 153  
  154 + function createDropActions(record: any) {
  155 + if (!record.editable) {
  156 + const actions = [
  157 + {
  158 + label: '历史记录',
  159 + onClick: handleHistoryDetail.bind(null, record),
  160 + },
  161 + ];
  162 + return actions;
  163 + }
  164 + }
  165 +
131 166 onMounted(async () => {
132 167 await orderStore.getDict();
133 168 });
... ... @@ -175,5 +210,25 @@
175 210 reload();
176 211 }, 50);
177 212 }
  213 +
  214 + async function handleStatus(record, status) {
  215 + try {
  216 + // Add your API call here for updating status
  217 + // Example: await updateStatus({ id: record.id, status: status ? 1 : 2 });
  218 + reload();
  219 + } catch (error) {
  220 + console.error(error);
  221 + }
  222 + }
  223 +
  224 + function handleHistoryDetail(record) {
  225 + openHistoryDetail(true, {
  226 + data: record,
  227 + });
  228 + }
  229 +
  230 + function handleGoFormDetail() {
  231 + // Add your logic for form detail navigation
  232 + }
178 233 </script>
179 234 <style></style>
... ...
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/HistoryDetail.vue 0 → 100644
  1 +<template>
  2 + <BasicDrawer
  3 + @register="register"
  4 + v-bind="$attrs"
  5 + title="操作记录"
  6 + width="60%"
  7 + :isDetail="true"
  8 + :showDetailBack="false"
  9 + okText="保存"
  10 + :destroyOnClose="true"
  11 + >
  12 + <Tabs v-model:activeKey="activeKey" className="my-0">
  13 + <TabPanel :key="1" tab="操作记录" className="w-full">
  14 + <a-list :pagination="pagination1" className="w-full">
  15 + <template v-for="item in list1" :key="item.id">
  16 + <a-list-item class="list">
  17 + <a-list-item-meta>
  18 + <template #avatar> </template>
  19 + <template #title>
  20 + <span>{{ item.userName }}</span>
  21 + </template>
  22 + <template #description>
  23 + <div class="description">
  24 + {{ item.optType }}
  25 + </div>
  26 + <div class="info">
  27 + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div>
  28 + </div>
  29 + </template>
  30 + </a-list-item-meta>
  31 + </a-list-item>
  32 + </template>
  33 + </a-list>
  34 + </TabPanel>
  35 + <TabPanel :key="2" tab="审批记录" className="w-full">
  36 + <a-list :pagination="pagination2" className="w-full">
  37 + <template v-for="item in list2" :key="item.id">
  38 + <a-list-item class="list">
  39 + <a-list-item-meta>
  40 + <template #avatar> </template>
  41 + <template #title>
  42 + <span>{{ item.userName }}</span>
  43 + </template>
  44 + <template #description>
  45 + <div class="description">
  46 + {{ item.optType }}
  47 + </div>
  48 + <div class="info">
  49 + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div>
  50 + </div>
  51 + </template>
  52 + </a-list-item-meta>
  53 + </a-list-item>
  54 + </template>
  55 + </a-list>
  56 + </TabPanel>
  57 + </Tabs>
  58 +
  59 + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
  60 + <template #appendFooter>
  61 + <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> -->
  62 + </template>
  63 + </BasicDrawer>
  64 +</template>
  65 +<script lang="ts">
  66 + import { defineComponent, ref, computed } from 'vue';
  67 + import { Tabs, List } from 'ant-design-vue';
  68 + import { FormSchema } from '/@/components/Form/index';
  69 +
  70 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  71 + import { getProjectOptLog } from '/@/api/project/invoice';
  72 + import { formatToDateTime } from '/@/utils/dateUtil';
  73 +
  74 + const TabPanel = Tabs.TabPane;
  75 +
  76 + const schemas: FormSchema[] = [
  77 + {
  78 + field: '订单号',
  79 + component: 'Input',
  80 + label: '字段1',
  81 + componentProps: {
  82 + readonly: true,
  83 + disabled: true,
  84 + },
  85 + colProps: {
  86 + span: 12,
  87 + },
  88 + defaultValue: '111',
  89 + },
  90 + {
  91 + field: 'field2',
  92 + component: 'Input',
  93 + label: '字段2',
  94 + colProps: {
  95 + span: 12,
  96 + },
  97 + },
  98 + ];
  99 + const achieveList = [
  100 + {
  101 + key: '1',
  102 + name: '操作记录',
  103 + },
  104 + {
  105 + key: '2',
  106 + name: '审批记录',
  107 + },
  108 + ];
  109 + export default defineComponent({
  110 + components: {
  111 + BasicDrawer,
  112 + Tabs,
  113 + TabPanel,
  114 + [List.name]: List,
  115 + [List.Item.name]: List.Item,
  116 + AListItemMeta: List.Item.Meta,
  117 + },
  118 + props: {
  119 + onGoCheckDetail: {
  120 + type: Function,
  121 + },
  122 + },
  123 + setup() {
  124 + const list1 = ref([]);
  125 + const total1 = ref(0);
  126 + const page1 = ref(1);
  127 +
  128 + const list2 = ref([]);
  129 + const total2 = ref(0);
  130 + const page2 = ref(1);
  131 + const orderId = ref('');
  132 + const activeKey = ref(1);
  133 +
  134 + const getOrderOptLogFunc = async (data, index, page) => {
  135 + console.log('%c [ data ]-135', 'font-size:13px; background:pink; color:#bf2c9f;', data);
  136 + if (index === 1) {
  137 + const res = await getProjectOptLog({ orderId: data, type: 30, page: page, pageSize: 20 });
  138 + list1.value = res.items;
  139 + total1.value = res.total;
  140 + page1.value = page;
  141 + } else {
  142 + const res = await getProjectOptLog({ orderId: data, type: 1, page: page, pageSize: 20 });
  143 + list2.value = res.items;
  144 + total2.value = res.total;
  145 + page2.value = page;
  146 + }
  147 + };
  148 + const [register] = useDrawerInner((data) => {
  149 + orderId.value = data.data.projectNoPrefix;
  150 + getOrderOptLogFunc(orderId.value, 1, 1);
  151 + getOrderOptLogFunc(orderId.value, 2, 1);
  152 + });
  153 +
  154 + const pagination1 = computed(() => {
  155 + return {
  156 + show: true,
  157 + pageSize: 20,
  158 + page: page1.value,
  159 + total: total1.value,
  160 + onChange(cur) {
  161 + getOrderOptLogFunc(orderId.value, 1, cur);
  162 + },
  163 + };
  164 + });
  165 +
  166 + const pagination2 = computed(() => {
  167 + return {
  168 + show: true,
  169 + pageSize: 20,
  170 + page: page1.value,
  171 + total: total1.value,
  172 + onChange(cur) {
  173 + getOrderOptLogFunc(orderId.value, 2, cur);
  174 + },
  175 + };
  176 + });
  177 +
  178 + return {
  179 + register,
  180 + schemas,
  181 + achieveList,
  182 + list1,
  183 + list2,
  184 + prefixCls: 'account-center',
  185 + pagination1,
  186 + pagination2,
  187 + activeKey,
  188 + formatToDateTime,
  189 + };
  190 + },
  191 + });
  192 +</script>
... ...
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/data.tsx
... ... @@ -241,6 +241,20 @@ export const COLUMNS = [
241 241 },
242 242 },
243 243 {
  244 + title: '状态',
  245 + dataIndex: 'status',
  246 + width: 120,
  247 + customRender: (column) => {
  248 + if (column.record?.status === '-1') {
  249 + return '未完成';
  250 + } else if (column.record?.status === '0') {
  251 + return '待审核';
  252 + } else if (column.record?.status === '1') {
  253 + return '已审核';
  254 + }
  255 + },
  256 + },
  257 + {
244 258 title: '文件',
245 259 dataIndex: 'fileUrl',
246 260 width: 120,
... ...
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/index.vue
... ... @@ -6,7 +6,10 @@
6 6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 7 </template>
8 8 <template v-if="column.key === 'action'">
9   - <TableAction :actions="createActions(record)" />
  9 + <TableAction
  10 + :actions="createActions(record)"
  11 + :dropDownActions="createDropActions(record)"
  12 + />
10 13 </template>
11 14 <!-- <template v-if="column.key === 'relationValue'">
12 15 <a-input
... ... @@ -32,8 +35,9 @@
32 35 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" />
33 36 </div>
34 37 </BasicModal> -->
35   - <CheckDetail @register="checkModalRegister" />
  38 + <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
36 39 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  40 + <HistoryDetail @register="registerHistoryDetail" />
37 41 </div>
38 42 </template>
39 43 <script setup lang="ts">
... ... @@ -42,11 +46,15 @@
42 46 import { searchFormSchema, COLUMNS } from './data';
43 47 import { BasicModal, useModal } from '/@/components/Modal';
44 48 import { useMessage } from '/@/hooks/web/useMessage';
45   - import { onMounted, ref } from 'vue';
  49 + import { onMounted, ref, computed } from 'vue';
46 50 import { useDrawer } from '/@/components/Drawer';
47 51 import FinanceEdit from './FinanceEdit.vue';
48 52 import CheckDetail from './CheckDetail.vue';
  53 + import HistoryDetail from './HistoryDetail.vue';
49 54 import { useOrderStoreWithOut } from '/@/store/modules/order';
  55 + import { useUserStoreWithOut } from '/@/store/modules/user';
  56 + import { RoleEnum } from '/@/enums/roleEnum';
  57 + import { ROLE } from '../../../type.d';
50 58  
51 59 const { createMessage } = useMessage();
52 60 const { error } = createMessage;
... ... @@ -54,6 +62,12 @@
54 62 const orderStore = useOrderStoreWithOut();
55 63 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
56 64 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer();
  65 + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer();
  66 + const userStore = useUserStoreWithOut();
  67 + const user = userStore.getUserInfo;
  68 + const role = computed(() => {
  69 + return user?.roleSmallVO?.code;
  70 + });
57 71 const handleOk = (record) => {
58 72 // 修改父组件的状态
59 73 closeModal();
... ... @@ -81,7 +95,7 @@
81 95 setting: false,
82 96 },
83 97 actionColumn: {
84   - width: 240,
  98 + width: 260,
85 99 title: 'Action',
86 100 dataIndex: 'action',
87 101 },
... ... @@ -113,6 +127,18 @@
113 127 // },
114 128 onClick: handleFalse.bind(null, record),
115 129 },
  130 + {
  131 + label: '审核通过',
  132 + popConfirm: {
  133 + title: '确认审核?',
  134 + confirm: () => {
  135 + if (record.status === 0 && role.value === ROLE.ADMIN) {
  136 + handleStatus(record, true);
  137 + }
  138 + return;
  139 + },
  140 + },
  141 + },
116 142 ];
117 143 }
118 144 return [
... ... @@ -130,6 +156,18 @@
130 156 ];
131 157 }
132 158  
  159 + function createDropActions(record: any) {
  160 + if (!record.editable) {
  161 + const actions = [
  162 + {
  163 + label: '历史记录',
  164 + onClick: handleHistoryDetail.bind(null, record),
  165 + },
  166 + ];
  167 + return actions;
  168 + }
  169 + }
  170 +
133 171 onMounted(async () => {
134 172 await orderStore.getDict();
135 173 });
... ... @@ -173,5 +211,25 @@
173 211 reload();
174 212 }, 50);
175 213 }
  214 +
  215 + async function handleStatus(record, status) {
  216 + try {
  217 + // Add your API call here for updating status
  218 + // Example: await updateStatus({ id: record.id, status: status ? 1 : 2 });
  219 + reload();
  220 + } catch (error) {
  221 + console.error(error);
  222 + }
  223 + }
  224 +
  225 + function handleHistoryDetail(record) {
  226 + openHistoryDetail(true, {
  227 + data: record,
  228 + });
  229 + }
  230 +
  231 + function handleGoFormDetail() {
  232 + // Add your logic for form detail navigation
  233 + }
176 234 </script>
177 235 <style></style>
... ...
src/views/project/finance/financeProfit/ServiceProfit/PackageProfit/HistoryDetail.vue 0 → 100644
  1 +<template>
  2 + <BasicDrawer
  3 + @register="register"
  4 + v-bind="$attrs"
  5 + title="操作记录"
  6 + width="60%"
  7 + :isDetail="true"
  8 + :showDetailBack="false"
  9 + okText="保存"
  10 + :destroyOnClose="true"
  11 + >
  12 + <Tabs v-model:activeKey="activeKey" className="my-0">
  13 + <TabPanel :key="1" tab="操作记录" className="w-full">
  14 + <a-list :pagination="pagination1" className="w-full">
  15 + <template v-for="item in list1" :key="item.id">
  16 + <a-list-item class="list">
  17 + <a-list-item-meta>
  18 + <template #avatar> </template>
  19 + <template #title>
  20 + <span>{{ item.userName }}</span>
  21 + </template>
  22 + <template #description>
  23 + <div class="description">
  24 + {{ item.optType }}
  25 + </div>
  26 + <div class="info">
  27 + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div>
  28 + </div>
  29 + </template>
  30 + </a-list-item-meta>
  31 + </a-list-item>
  32 + </template>
  33 + </a-list>
  34 + </TabPanel>
  35 + <TabPanel :key="2" tab="审批记录" className="w-full">
  36 + <a-list :pagination="pagination2" className="w-full">
  37 + <template v-for="item in list2" :key="item.id">
  38 + <a-list-item class="list">
  39 + <a-list-item-meta>
  40 + <template #avatar> </template>
  41 + <template #title>
  42 + <span>{{ item.userName }}</span>
  43 + </template>
  44 + <template #description>
  45 + <div class="description">
  46 + {{ item.optType }}
  47 + </div>
  48 + <div class="info">
  49 + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div>
  50 + </div>
  51 + </template>
  52 + </a-list-item-meta>
  53 + </a-list-item>
  54 + </template>
  55 + </a-list>
  56 + </TabPanel>
  57 + </Tabs>
  58 +
  59 + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
  60 + <template #appendFooter>
  61 + <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> -->
  62 + </template>
  63 + </BasicDrawer>
  64 +</template>
  65 +<script lang="ts">
  66 + import { defineComponent, ref, computed } from 'vue';
  67 + import { Tabs, Progress, Row, Col, List } from 'ant-design-vue';
  68 + import { FormSchema, useForm } from '/@/components/Form/index';
  69 +
  70 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  71 + import { getOrderCostDetailedOptLog } from '/@/api/project/invoice';
  72 + import { formatToDateTime } from '/@/utils/dateUtil';
  73 +
  74 + const TabPanel = Tabs.TabPane;
  75 +
  76 + const schemas: FormSchema[] = [
  77 + {
  78 + field: '订单号',
  79 + component: 'Input',
  80 + label: '字段1',
  81 + componentProps: {
  82 + readonly: true,
  83 + disabled: true,
  84 + },
  85 + colProps: {
  86 + span: 12,
  87 + },
  88 + defaultValue: '111',
  89 + },
  90 + {
  91 + field: 'field2',
  92 + component: 'Input',
  93 + label: '字段2',
  94 + colProps: {
  95 + span: 12,
  96 + },
  97 + },
  98 + ];
  99 + const achieveList = [
  100 + {
  101 + key: '1',
  102 + name: '操作记录',
  103 + },
  104 + {
  105 + key: '2',
  106 + name: '审批记录',
  107 + },
  108 + ];
  109 + export default defineComponent({
  110 + components: {
  111 + BasicDrawer,
  112 + Tabs,
  113 + TabPanel,
  114 + [List.name]: List,
  115 + [List.Item.name]: List.Item,
  116 + AListItemMeta: List.Item.Meta,
  117 + },
  118 + props: {
  119 + onGoCheckDetail: {
  120 + type: Function,
  121 + },
  122 + },
  123 + setup() {
  124 + const list1 = ref([]);
  125 + const total1 = ref(0);
  126 + const page1 = ref(1);
  127 +
  128 + const list2 = ref([]);
  129 + const total2 = ref(0);
  130 + const page2 = ref(1);
  131 + const orderId = ref('');
  132 + const activeKey = ref(1);
  133 +
  134 + const getOrderOptLogFunc = async (data, index, page) => {
  135 + console.log('%c [ data ]-135', 'font-size:13px; background:pink; color:#bf2c9f;', data);
  136 + if (index === 1) {
  137 + const res = await getOrderCostDetailedOptLog({
  138 + orderId: data,
  139 + type: 20,
  140 + page: page,
  141 + pageSize: 20
  142 + });
  143 + list1.value = res.items;
  144 + total1.value = res.total;
  145 + page1.value = page;
  146 + } else {
  147 + const res = await getOrderCostDetailedOptLog({
  148 + orderId: data,
  149 + type: 60,
  150 + page: page,
  151 + pageSize: 20
  152 + });
  153 + list2.value = res.items;
  154 + total2.value = res.total;
  155 + page2.value = page;
  156 + }
  157 + };
  158 + const [register] = useDrawerInner((data) => {
  159 + orderId.value = data.data.orderId;
  160 + getOrderOptLogFunc(orderId.value, 1, 1);
  161 + getOrderOptLogFunc(orderId.value, 2, 1);
  162 + });
  163 +
  164 + const pagination1 = computed(() => {
  165 + return {
  166 + show: true,
  167 + pageSize: 20,
  168 + page: page1.value,
  169 + total: total1.value,
  170 + onChange(cur) {
  171 + getOrderOptLogFunc(orderId.value, 1, cur);
  172 + },
  173 + };
  174 + });
  175 +
  176 + const pagination2 = computed(() => {
  177 + return {
  178 + show: true,
  179 + pageSize: 20,
  180 + page: page1.value,
  181 + total: total1.value,
  182 + onChange(cur) {
  183 + getOrderOptLogFunc(orderId.value, 2, cur);
  184 + },
  185 + };
  186 + });
  187 +
  188 + return {
  189 + register,
  190 + schemas,
  191 + achieveList,
  192 + list1,
  193 + list2,
  194 + prefixCls: 'account-center',
  195 + pagination1,
  196 + pagination2,
  197 + activeKey,
  198 + formatToDateTime,
  199 + };
  200 + },
  201 + });
  202 +</script>
... ...
src/views/project/finance/financeProfit/ServiceProfit/PackageProfit/data.tsx
... ... @@ -187,4 +187,18 @@ export const COLUMNS = [
187 187 return column.record?.packetProfitRate?.toFixed(2);
188 188 },
189 189 },
  190 + {
  191 + title: '状态',
  192 + dataIndex: 'status',
  193 + width: 120,
  194 + customRender: (column) => {
  195 + if (column.record?.status === '-1') {
  196 + return '未完成';
  197 + } else if (column.record?.status === '0') {
  198 + return '待审核';
  199 + } else if (column.record?.status === '1') {
  200 + return '已审核';
  201 + }
  202 + },
  203 + },
190 204 ];
191 205 \ No newline at end of file
... ...
src/views/project/finance/financeProfit/ServiceProfit/PackageProfit/index.vue
... ... @@ -6,7 +6,10 @@
6 6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 7 </template>
8 8 <template v-if="column.key === 'action'">
9   - <TableAction :actions="createActions(record)" />
  9 + <TableAction
  10 + :actions="createActions(record)"
  11 + :dropDownActions="createDropActions(record)"
  12 + />
10 13 </template>
11 14 <!-- <template v-if="column.key === 'relationValue'">
12 15 <a-input
... ... @@ -34,6 +37,7 @@
34 37 </BasicModal> -->
35 38 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
36 39 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  40 + <HistoryDetail @register="registerHistoryDetail" />
37 41 </div>
38 42 </template>
39 43 <script setup lang="ts">
... ... @@ -42,12 +46,16 @@
42 46 import { searchFormSchema, COLUMNS } from './data';
43 47 import { BasicModal, useModal } from '/@/components/Modal';
44 48 import { useMessage } from '/@/hooks/web/useMessage';
45   - import { onMounted, ref } from 'vue';
  49 + import { onMounted, ref, computed } from 'vue';
46 50 import { useDrawer } from '/@/components/Drawer';
47 51 import FinanceEdit from './FinanceEdit.vue';
48 52 import CheckDetail from './CheckDetail.vue';
  53 + import HistoryDetail from './HistoryDetail.vue';
49 54 import { FilePptOutlined } from '@ant-design/icons-vue';
50 55 import { useOrderStoreWithOut } from '/@/store/modules/order';
  56 + import { useUserStoreWithOut } from '/@/store/modules/user';
  57 + import { RoleEnum } from '/@/enums/roleEnum';
  58 + import { ROLE } from '../../../type.d';
51 59  
52 60 const { createMessage } = useMessage();
53 61 const { error } = createMessage;
... ... @@ -55,6 +63,12 @@
55 63 const orderStore = useOrderStoreWithOut();
56 64 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
57 65 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer();
  66 + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer();
  67 + const userStore = useUserStoreWithOut();
  68 + const user = userStore.getUserInfo;
  69 + const role = computed(() => {
  70 + return user?.roleSmallVO?.code;
  71 + });
58 72 const handleOk = (record) => {
59 73 // 修改父组件的状态
60 74 closeModal();
... ... @@ -81,7 +95,7 @@
81 95 setting: false,
82 96 },
83 97 actionColumn: {
84   - width: 240,
  98 + width: 260,
85 99 title: 'Action',
86 100 dataIndex: 'action',
87 101 },
... ... @@ -113,6 +127,18 @@
113 127 // },
114 128 onClick: handleFalse.bind(null, record),
115 129 },
  130 + {
  131 + label: '审核通过',
  132 + popConfirm: {
  133 + title: '确认审核?',
  134 + confirm: () => {
  135 + if (record.status === 0 && role.value === ROLE.ADMIN) {
  136 + handleStatus(record, true);
  137 + }
  138 + return;
  139 + },
  140 + },
  141 + },
116 142 ];
117 143 }
118 144 return [
... ... @@ -130,9 +156,17 @@
130 156 ];
131 157 }
132 158  
133   - onMounted(async () => {
134   - await orderStore.getDict();
135   - });
  159 + function createDropActions(record: any) {
  160 + if (!record.editable) {
  161 + const actions = [
  162 + {
  163 + label: '历史记录',
  164 + onClick: handleHistoryDetail.bind(null, record),
  165 + },
  166 + ];
  167 + return actions;
  168 + }
  169 + }
136 170  
137 171 function handleFinanceEdit(record) {
138 172 openFinanceEdit(true, {
... ... @@ -176,5 +210,29 @@
176 210 // await deleteConfig({ ids: [record.id] });
177 211 // reload();
178 212 // }
  213 +
  214 + async function handleStatus(record, status) {
  215 + try {
  216 + // Add your API call here for updating status
  217 + // Example: await updateStatus({ id: record.id, status: status ? 1 : 2 });
  218 + reload();
  219 + } catch (error) {
  220 + console.error(error);
  221 + }
  222 + }
  223 +
  224 + function handleHistoryDetail(record) {
  225 + openHistoryDetail(true, {
  226 + data: record,
  227 + });
  228 + }
  229 +
  230 + function handleGoFormDetail() {
  231 + // Add your logic for form detail navigation
  232 + }
  233 +
  234 + onMounted(async () => {
  235 + await orderStore.getDict();
  236 + });
179 237 </script>
180 238 <style></style>
... ...
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/HistoryDetail.vue 0 → 100644
  1 +<template>
  2 + <BasicDrawer
  3 + @register="register"
  4 + v-bind="$attrs"
  5 + title="操作记录"
  6 + width="60%"
  7 + :isDetail="true"
  8 + :showDetailBack="false"
  9 + okText="保存"
  10 + :destroyOnClose="true"
  11 + >
  12 + <Tabs v-model:activeKey="activeKey" className="my-0">
  13 + <TabPanel :key="1" tab="操作记录" className="w-full">
  14 + <a-list :pagination="pagination1" className="w-full">
  15 + <template v-for="item in list1" :key="item.id">
  16 + <a-list-item class="list">
  17 + <a-list-item-meta>
  18 + <template #avatar> </template>
  19 + <template #title>
  20 + <span>{{ item.userName }}</span>
  21 + </template>
  22 + <template #description>
  23 + <div class="description">
  24 + {{ item.optType }}
  25 + </div>
  26 + <div class="info">
  27 + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div>
  28 + </div>
  29 + </template>
  30 + </a-list-item-meta>
  31 + </a-list-item>
  32 + </template>
  33 + </a-list>
  34 + </TabPanel>
  35 + <TabPanel :key="2" tab="审批记录" className="w-full">
  36 + <a-list :pagination="pagination2" className="w-full">
  37 + <template v-for="item in list2" :key="item.id">
  38 + <a-list-item class="list">
  39 + <a-list-item-meta>
  40 + <template #avatar> </template>
  41 + <template #title>
  42 + <span>{{ item.userName }}</span>
  43 + </template>
  44 + <template #description>
  45 + <div class="description">
  46 + {{ item.optType }}
  47 + </div>
  48 + <div class="info">
  49 + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div>
  50 + </div>
  51 + </template>
  52 + </a-list-item-meta>
  53 + </a-list-item>
  54 + </template>
  55 + </a-list>
  56 + </TabPanel>
  57 + </Tabs>
  58 +
  59 + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
  60 + <template #appendFooter>
  61 + <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> -->
  62 + </template>
  63 + </BasicDrawer>
  64 +</template>
  65 +<script lang="ts">
  66 + import { defineComponent, ref, computed } from 'vue';
  67 + import { Tabs, Progress, Row, Col, List } from 'ant-design-vue';
  68 + import { FormSchema, useForm } from '/@/components/Form/index';
  69 +
  70 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  71 + import { getProjectOptLog } from '/@/api/project/invoice';
  72 + import { formatToDateTime } from '/@/utils/dateUtil';
  73 +
  74 + const TabPanel = Tabs.TabPane;
  75 +
  76 + const schemas: FormSchema[] = [
  77 + {
  78 + field: '订单号',
  79 + component: 'Input',
  80 + label: '字段1',
  81 + componentProps: {
  82 + readonly: true,
  83 + disabled: true,
  84 + },
  85 + colProps: {
  86 + span: 12,
  87 + },
  88 + defaultValue: '111',
  89 + },
  90 + {
  91 + field: 'field2',
  92 + component: 'Input',
  93 + label: '字段2',
  94 + colProps: {
  95 + span: 12,
  96 + },
  97 + },
  98 + ];
  99 + const achieveList = [
  100 + {
  101 + key: '1',
  102 + name: '操作记录',
  103 + },
  104 + {
  105 + key: '2',
  106 + name: '审批记录',
  107 + },
  108 + ];
  109 + export default defineComponent({
  110 + components: {
  111 + BasicDrawer,
  112 + Tabs,
  113 + TabPanel,
  114 + [List.name]: List,
  115 + [List.Item.name]: List.Item,
  116 + AListItemMeta: List.Item.Meta,
  117 + },
  118 + props: {
  119 + onGoCheckDetail: {
  120 + type: Function,
  121 + },
  122 + },
  123 + setup() {
  124 + const list1 = ref([]);
  125 + const total1 = ref(0);
  126 + const page1 = ref(1);
  127 +
  128 + const list2 = ref([]);
  129 + const total2 = ref(0);
  130 + const page2 = ref(1);
  131 + const orderId = ref('');
  132 + const activeKey = ref(1);
  133 +
  134 + const getOrderOptLogFunc = async (data, index, page) => {
  135 + console.log('%c [ data ]-135', 'font-size:13px; background:pink; color:#bf2c9f;', data);
  136 + if (index === 1) {
  137 + const res = await getProjectOptLog({
  138 + projectNoPrefix: data,
  139 + type: 10,
  140 + page: page,
  141 + pageSize: 20
  142 + });
  143 + console.log(res, '5656res');
  144 + list1.value = res.items;
  145 + total1.value = res.total;
  146 + page1.value = page;
  147 + } else {
  148 + const res = await getProjectOptLog({
  149 + projectNoPrefix: data,
  150 + type: 0,
  151 + page: page,
  152 + pageSize: 20
  153 + });
  154 + list2.value = res.items;
  155 + total2.value = res.total;
  156 + page2.value = page;
  157 + }
  158 + };
  159 + const [register] = useDrawerInner((data) => {
  160 + orderId.value = data.data.projectNoPrefix;
  161 + getOrderOptLogFunc(orderId.value, 1, 1);
  162 + getOrderOptLogFunc(orderId.value, 2, 1);
  163 + });
  164 +
  165 + const pagination1 = computed(() => {
  166 + return {
  167 + show: true,
  168 + pageSize: 20,
  169 + page: page1.value,
  170 + total: total1.value,
  171 + onChange(cur) {
  172 + getOrderOptLogFunc(orderId.value, 1, cur);
  173 + },
  174 + };
  175 + });
  176 +
  177 + const pagination2 = computed(() => {
  178 + return {
  179 + show: true,
  180 + pageSize: 20,
  181 + page: page1.value,
  182 + total: total1.value,
  183 + onChange(cur) {
  184 + getOrderOptLogFunc(orderId.value, 2, cur);
  185 + },
  186 + };
  187 + });
  188 +
  189 + return {
  190 + register,
  191 + schemas,
  192 + achieveList,
  193 + list1,
  194 + list2,
  195 + prefixCls: 'account-center',
  196 + pagination1,
  197 + pagination2,
  198 + activeKey,
  199 + formatToDateTime,
  200 + };
  201 + },
  202 + });
  203 +</script>
... ...
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/data.tsx
... ... @@ -140,7 +140,6 @@ export const COLUMNS = [
140 140 dataIndex: 'packetTotalPrice',
141 141 width: 150,
142 142 customRender: (column) => {
143   - console.log(column, '5656666666');
144 143 return column.record?.packetRmbTotalPrice?.toFixed(2);
145 144 },
146 145 },
... ... @@ -311,14 +310,6 @@ export const COLUMNS = [
311 310 },
312 311 },
313 312 {
314   - title: '汇率收益¥',
315   - dataIndex: 'exchangeRateProfit',
316   - width: 120,
317   - customRender: (column) => {
318   - return column.record?.exchangeRateProfit?.toFixed(2);
319   - },
320   - },
321   - {
322 313 title: '综合收益¥',
323 314 dataIndex: 'comprehensiveProfit',
324 315 width: 120,
... ... @@ -381,4 +372,18 @@ export const COLUMNS = [
381 372 return <FilePptOutlined style="font-size:25px" onClick={() => handleClick()} />;
382 373 },
383 374 },
  375 + {
  376 + title: '状态',
  377 + dataIndex: 'status',
  378 + width: 120,
  379 + customRender: (column) => {
  380 + if (column.record?.status === '-1') {
  381 + return '未完成';
  382 + } else if (column.record?.status === '0') {
  383 + return '待审核';
  384 + } else if (column.record?.status === '1') {
  385 + return '已审核';
  386 + }
  387 + },
  388 + },
384 389 ];
385 390 \ No newline at end of file
... ...
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/index.vue
... ... @@ -3,7 +3,10 @@
3 3 <BasicTable @register="registerTable" :bordered="true">
4 4 <template #bodyCell="{ column, record }">
5 5 <template v-if="column.key === 'action'">
6   - <TableAction :actions="createActions(record)" />
  6 + <TableAction
  7 + :actions="createActions(record)"
  8 + :dropDownActions="createDropActions(record)"
  9 + />
7 10 </template>
8 11 <!-- <template v-if="column.key === 'relationValue'">
9 12 <a-input
... ... @@ -31,32 +34,39 @@
31 34 </BasicModal> -->
32 35 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
33 36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  37 + <HistoryDetail @register="registerHistoryDetail" />
34 38 </div>
35 39 </template>
36 40 <script setup lang="ts">
37 41 import { BasicTable, useTable, TableAction } from '/@/components/Table';
38 42 import { getServiceProfit } from '@/api/project/invoice';
39 43 import { searchFormSchema, COLUMNS } from './data';
40   - import { BasicModal, useModal } from '/@/components/Modal';
41 44 import { useMessage } from '/@/hooks/web/useMessage';
42   - import { onMounted, ref } from 'vue';
  45 + import { onMounted, ref, computed, unref } from 'vue';
43 46 import { useDrawer } from '/@/components/Drawer';
44 47 import FinanceEdit from './FinanceEdit.vue';
  48 + import HistoryDetail from './HistoryDetail.vue';
45 49 import CheckDetail from './CheckDetail.vue';
  50 + import { useUserStoreWithOut } from '/@/store/modules/user';
  51 + import { ROLE } from '../../../type.d';
46 52 import { useOrderStoreWithOut } from '/@/store/modules/order';
47 53  
48 54 const { createMessage } = useMessage();
49   - const { error } = createMessage;
50 55 const message = ref();
  56 + const checkedKeys = ref<string[]>([]);
  57 + const invoiceIdKeys = ref<string[]>([]);
  58 + const checkIdKeys = ref<string[]>([]);
51 59 const orderStore = useOrderStoreWithOut();
52 60 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
53 61 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer();
54   - const handleClose = (visible: boolean) => {
55   - if (!visible) {
56   - message.value = '';
57   - }
58   - };
59   - const [registerTable, { reload }] = useTable({
  62 + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer();
  63 + const userStore = useUserStoreWithOut();
  64 + const user = userStore.getUserInfo;
  65 + const role = computed(() => {
  66 + return user?.roleSmallVO?.code;
  67 + });
  68 + const [registerTable, { reload, getSelectRowKeys, getDataSource, setSelectedRowKeys }] = useTable({
  69 +
60 70 api: getServiceProfit,
61 71 bordered: true,
62 72 columns: COLUMNS,
... ... @@ -74,7 +84,7 @@
74 84 setting: false,
75 85 },
76 86 actionColumn: {
77   - width: 240,
  87 + width: 260,
78 88 title: 'Action',
79 89 dataIndex: 'action',
80 90 },
... ... @@ -82,7 +92,7 @@
82 92  
83 93 function createActions(record: any): any[] {
84 94 if (!record.editable) {
85   - return [
  95 + const actions = [
86 96 {
87 97 label: '财务编辑',
88 98 onClick: handleFinanceEdit.bind(null, record),
... ... @@ -106,7 +116,20 @@
106 116 // },
107 117 onClick: handleFalse.bind(null, record),
108 118 },
  119 + {
  120 + label: '审核通过',
  121 + popConfirm: {
  122 + title: '确认审核?',
  123 + confirm: () => {
  124 + if (record.status === 0 && role.value === ROLE.ADMIN) {
  125 + handleStatus(record, true);
  126 + }
  127 + return;
  128 + },
  129 + },
  130 + },
109 131 ];
  132 + return actions;
110 133 }
111 134 return [
112 135 {
... ... @@ -122,6 +145,17 @@
122 145 },
123 146 ];
124 147 }
  148 + function createDropActions(record: any) {
  149 + if (!record.editable) {
  150 + const actions = [
  151 + {
  152 + label: '历史记录',
  153 + onClick: handleHistoryDetail.bind(null, record),
  154 + },
  155 + ];
  156 + return actions;
  157 + }
  158 + }
125 159  
126 160 onMounted(async () => {
127 161 await orderStore.getDict();
... ... @@ -160,7 +194,6 @@
160 194 // error('请勿连续点击生成按钮,需要等待三秒再点击生成');
161 195 // } else {
162 196 record.onEdit?.(true);
163   - // }
164 197 }
165 198  
166 199 function handleCancel(record) {
... ... @@ -171,5 +204,21 @@
171 204 // await deleteConfig({ ids: [record.id] });
172 205 reload();
173 206 }
  207 +
  208 + async function handleStatus(record, status) {
  209 + try {
  210 + // You can implement the API call here
  211 + // await someApiCall({ id: record.id, status });
  212 + reload();
  213 + } catch (error) {
  214 + console.error('Error updating status:', error);
  215 + }
  216 + }
  217 +
  218 + async function handleHistoryDetail(record) {
  219 + openHistoryDetail(true, {
  220 + data: record,
  221 + });
  222 + }
174 223 </script>
175 224 <style></style>
... ...
src/views/project/finance/type.d.ts 0 → 100644
  1 +export enum ROLE {
  2 + ADMIN = 'admin', // 超管
  3 + CUSTOM_ADMIN = 'custom_admin', // 客户管理员
  4 + DATA_REPORT_USER = 'data_report_user', //数据分析员
  5 + BUSINESS = 'business_user', // 业务员
  6 + TRACKER = 'tracker_user', // 跟单员
  7 + INSPECT = 'inspect_user', // 质检员
  8 + PRODUCE = 'produce_user', //生产科
  9 + FINANCE = 'finance_user', //财务
  10 +}
... ...