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,12 +21,11 @@ export const approveAuditApi = async (params: any) =>
21 { message: '操作成功' }, 21 { message: '操作成功' },
22 ); 22 );
23 23
24 -export const getWaitListApi = async (params: DemoParams) => { 24 +export const getWaitListApi = async (params: any) => {
25 const res = await defHttp.post({ 25 const res = await defHttp.post({
26 url: Api.APPROVE, 26 url: Api.APPROVE,
27 params, 27 params,
28 }); 28 });
29 -  
30 res.records = res.records.map((item) => { 29 res.records = res.records.map((item) => {
31 return item; 30 return item;
32 }); 31 });
@@ -44,7 +43,7 @@ export const getApprovedListApi = async (params: any) => { @@ -44,7 +43,7 @@ export const getApprovedListApi = async (params: any) => {
44 res.records = res.records.map((item) => { 43 res.records = res.records.map((item) => {
45 return item; 44 return item;
46 }); 45 });
47 - 46 + console.log(res, '56567ressss');
48 return new Promise((resolve) => { 47 return new Promise((resolve) => {
49 resolve({ items: res.records, total: res.total }); 48 resolve({ items: res.records, total: res.total });
50 }); 49 });
src/api/project/invoice.ts
@@ -50,6 +50,12 @@ enum Api { @@ -50,6 +50,12 @@ enum Api {
50 SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请修改 50 SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请修改
51 APPLYLIST = '/project/pageProjectLockFieldApply', //分页查询项目字段申请记录 51 APPLYLIST = '/project/pageProjectLockFieldApply', //分页查询项目字段申请记录
52 AUDITAPPLY = '/project/audit', //审核 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 export const getRefundDate = async (params: any, data?: any) => { 61 export const getRefundDate = async (params: any, data?: any) => {
@@ -427,18 +433,30 @@ export const getServiceApplyEdit = async (params: any) => { @@ -427,18 +433,30 @@ export const getServiceApplyEdit = async (params: any) => {
427 }; 433 };
428 434
429 export const getApplyList = async (params: any) => { 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 url: Api.APPLYLIST, 449 url: Api.APPLYLIST,
433 params, 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 export const getAuditApply = async (params: any) => { 462 export const getAuditApply = async (params: any) => {
@@ -461,3 +479,70 @@ export const checkDeleteDeduct = async (params: any) =&gt; { @@ -461,3 +479,70 @@ export const checkDeleteDeduct = async (params: any) =&gt; {
461 params, 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 \ No newline at end of file 549 \ No newline at end of file
src/router/routes/modules/project/finance.ts
@@ -116,8 +116,8 @@ const finance: AppRouteModule = { @@ -116,8 +116,8 @@ const finance: AppRouteModule = {
116 }, 116 },
117 children: [ 117 children: [
118 { 118 {
119 - path: 'InnerData',  
120 - name: 'InnerData', 119 + path: 'InnerProduce',
  120 + name: 'InnerProduce',
121 meta: { 121 meta: {
122 title: '内部生产净利润分析表', 122 title: '内部生产净利润分析表',
123 roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS], 123 roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
@@ -129,8 +129,8 @@ const finance: AppRouteModule = { @@ -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 meta: { 134 meta: {
135 title: '内部生产明细表', 135 title: '内部生产明细表',
136 roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS], 136 roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
src/views/project/finance/financeProfit/ProductProfit/InnerData/FinanceEdit.vue
@@ -32,6 +32,14 @@ @@ -32,6 +32,14 @@
32 auto-size 32 auto-size
33 /> 33 />
34 <div style="margin: 16px 0"></div> 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 <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> --> 44 <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
37 <template #appendFooter> 45 <template #appendFooter>
@@ -126,20 +134,26 @@ @@ -126,20 +134,26 @@
126 const update = ref(); 134 const update = ref();
127 const status1 = ref(); 135 const status1 = ref();
128 const status2 = ref(); 136 const status2 = ref();
  137 + const status3 = ref();
129 138
130 const input1 = ref(); 139 const input1 = ref();
131 const input2 = ref(); 140 const input2 = ref();
  141 + const input3 = ref();
  142 + const orderCount = ref();
132 const id = ref(); 143 const id = ref();
133 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => { 144 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => {
134 // 方式1 145 // 方式1
135 if (data.data?.lockFields) { 146 if (data.data?.lockFields) {
136 status1.value = data.data?.lockFields?.productionDepartmentPredictPrice; 147 status1.value = data.data?.lockFields?.productionDepartmentPredictPrice;
137 status2.value = data.data?.lockFields?.productionActualPrice; 148 status2.value = data.data?.lockFields?.productionActualPrice;
  149 + status3.value = data.data?.lockFields?.productionDepartmentPredictUnitprice;
138 } 150 }
139 151
140 id.value = data.data.orderId; 152 id.value = data.data.orderId;
141 input1.value = data.data?.productionDepartmentPredictPrice.toFixed(2); 153 input1.value = data.data?.productionDepartmentPredictPrice.toFixed(2);
142 input2.value = data.data?.productionActualPrice.toFixed(2); 154 input2.value = data.data?.productionActualPrice.toFixed(2);
  155 + orderCount.value = data.data?.orderCount;
  156 + input3.value = data.data?.productionDepartmentPredictUnitprice.toFixed(2);
143 resetFields(); 157 resetFields();
144 setDrawerProps({ confirmLoading: false }); 158 setDrawerProps({ confirmLoading: false });
145 // setFieldsValue({ 159 // setFieldsValue({
@@ -155,13 +169,15 @@ @@ -155,13 +169,15 @@
155 // id: update.value.data.id, 169 // id: update.value.data.id,
156 // bgUrl: update.value.data.bgUrl, 170 // bgUrl: update.value.data.bgUrl,
157 // }; 171 // };
158 - if (!input1.value || !input2.value) { 172 + if (!input1.value || !input2.value || !input3.value) {
159 error('选项不能为空'); 173 error('选项不能为空');
160 } else { 174 } else {
161 await getPackageEdit({ 175 await getPackageEdit({
162 orderId: id.value, 176 orderId: id.value,
163 productionDepartmentPredictPrice: input1.value, 177 productionDepartmentPredictPrice: input1.value,
164 productionActualPrice: input2.value, 178 productionActualPrice: input2.value,
  179 + orderCount: orderCount.value,
  180 + productionDepartmentPredictUnitprice: input3.value,
165 }); 181 });
166 emit('success'); 182 emit('success');
167 closeDrawer(); 183 closeDrawer();
@@ -171,6 +187,7 @@ @@ -171,6 +187,7 @@
171 if (!visible) { 187 if (!visible) {
172 input1.value = ''; 188 input1.value = '';
173 input2.value = ''; 189 input2.value = '';
  190 + input3.value = '';
174 } 191 }
175 } 192 }
176 </script> 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,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 width: 150, 149 width: 150,
142 dataIndex: 'productionDepartmentPredictPrice', 150 dataIndex: 'productionDepartmentPredictPrice',
143 customRender: (column) => { 151 customRender: (column) => {
@@ -145,9 +153,9 @@ export const COLUMNS = [ @@ -145,9 +153,9 @@ export const COLUMNS = [
145 }, 153 },
146 }, 154 },
147 { 155 {
148 - title: '实际发生费用', 156 + title: '生产科实际花费总金额¥',
149 dataIndex: 'productionActualPrice', 157 dataIndex: 'productionActualPrice',
150 - width: 120, 158 + width: 180,
151 customRender: (column) => { 159 customRender: (column) => {
152 return column.record?.productionActualPrice?.toFixed(2); 160 return column.record?.productionActualPrice?.toFixed(2);
153 }, 161 },
@@ -212,6 +220,20 @@ export const COLUMNS = [ @@ -212,6 +220,20 @@ export const COLUMNS = [
212 return column.record?.grossProfitRate?.toFixed(2); 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 // title: '内部生产固定成本¥', 238 // title: '内部生产固定成本¥',
217 // dataIndex: 'innerProductionFixedCost', 239 // dataIndex: 'innerProductionFixedCost',
src/views/project/finance/financeProfit/ProductProfit/InnerData/index.vue
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" /> 6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 </template> 7 </template>
8 <template v-if="column.key === 'action'"> 8 <template v-if="column.key === 'action'">
9 - <TableAction :actions="createActions(record)" /> 9 + <TableAction :actions="createActions(record)" :dropDownActions="createDropActions(record)" />
10 </template> 10 </template>
11 <!-- <template v-if="column.key === 'relationValue'"> 11 <!-- <template v-if="column.key === 'relationValue'">
12 <a-input 12 <a-input
@@ -32,8 +32,9 @@ @@ -32,8 +32,9 @@
32 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" /> 32 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" />
33 </div> 33 </div>
34 </BasicModal> --> 34 </BasicModal> -->
35 - <CheckDetail @register="checkModalRegister" /> 35 + <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> 36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  37 + <HistoryDetail @register="registerHistoryDetail" />
37 </div> 38 </div>
38 </template> 39 </template>
39 <script setup lang="ts"> 40 <script setup lang="ts">
@@ -42,11 +43,15 @@ @@ -42,11 +43,15 @@
42 import { searchFormSchema, COLUMNS } from './data'; 43 import { searchFormSchema, COLUMNS } from './data';
43 import { BasicModal, useModal } from '/@/components/Modal'; 44 import { BasicModal, useModal } from '/@/components/Modal';
44 import { useMessage } from '/@/hooks/web/useMessage'; 45 import { useMessage } from '/@/hooks/web/useMessage';
45 - import { onMounted, ref } from 'vue'; 46 + import { onMounted, ref, computed } from 'vue';
46 import { useDrawer } from '/@/components/Drawer'; 47 import { useDrawer } from '/@/components/Drawer';
47 import FinanceEdit from './FinanceEdit.vue'; 48 import FinanceEdit from './FinanceEdit.vue';
48 import CheckDetail from './CheckDetail.vue'; 49 import CheckDetail from './CheckDetail.vue';
  50 + import HistoryDetail from './HistoryDetail.vue';
49 import { useOrderStoreWithOut } from '/@/store/modules/order'; 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 const { createMessage } = useMessage(); 56 const { createMessage } = useMessage();
52 const { error } = createMessage; 57 const { error } = createMessage;
@@ -54,6 +59,12 @@ @@ -54,6 +59,12 @@
54 const orderStore = useOrderStoreWithOut(); 59 const orderStore = useOrderStoreWithOut();
55 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer(); 60 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
56 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); 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 const handleOk = (record) => { 68 const handleOk = (record) => {
58 // 修改父组件的状态 69 // 修改父组件的状态
59 closeModal(); 70 closeModal();
@@ -80,7 +91,7 @@ @@ -80,7 +91,7 @@
80 setting: false, 91 setting: false,
81 }, 92 },
82 actionColumn: { 93 actionColumn: {
83 - width: 240, 94 + width: 260,
84 title: 'Action', 95 title: 'Action',
85 dataIndex: 'action', 96 dataIndex: 'action',
86 }, 97 },
@@ -111,6 +122,18 @@ @@ -111,6 +122,18 @@
111 // }, 122 // },
112 onClick: handleFalse.bind(null, record), 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 return [ 139 return [
@@ -128,6 +151,18 @@ @@ -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 onMounted(async () => { 166 onMounted(async () => {
132 await orderStore.getDict(); 167 await orderStore.getDict();
133 }); 168 });
@@ -175,5 +210,25 @@ @@ -175,5 +210,25 @@
175 reload(); 210 reload();
176 }, 50); 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 </script> 233 </script>
179 <style></style> 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,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 title: '文件', 258 title: '文件',
245 dataIndex: 'fileUrl', 259 dataIndex: 'fileUrl',
246 width: 120, 260 width: 120,
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/index.vue
@@ -6,7 +6,10 @@ @@ -6,7 +6,10 @@
6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" /> 6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 </template> 7 </template>
8 <template v-if="column.key === 'action'"> 8 <template v-if="column.key === 'action'">
9 - <TableAction :actions="createActions(record)" /> 9 + <TableAction
  10 + :actions="createActions(record)"
  11 + :dropDownActions="createDropActions(record)"
  12 + />
10 </template> 13 </template>
11 <!-- <template v-if="column.key === 'relationValue'"> 14 <!-- <template v-if="column.key === 'relationValue'">
12 <a-input 15 <a-input
@@ -32,8 +35,9 @@ @@ -32,8 +35,9 @@
32 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" /> 35 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" />
33 </div> 36 </div>
34 </BasicModal> --> 37 </BasicModal> -->
35 - <CheckDetail @register="checkModalRegister" /> 38 + <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> 39 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  40 + <HistoryDetail @register="registerHistoryDetail" />
37 </div> 41 </div>
38 </template> 42 </template>
39 <script setup lang="ts"> 43 <script setup lang="ts">
@@ -42,11 +46,15 @@ @@ -42,11 +46,15 @@
42 import { searchFormSchema, COLUMNS } from './data'; 46 import { searchFormSchema, COLUMNS } from './data';
43 import { BasicModal, useModal } from '/@/components/Modal'; 47 import { BasicModal, useModal } from '/@/components/Modal';
44 import { useMessage } from '/@/hooks/web/useMessage'; 48 import { useMessage } from '/@/hooks/web/useMessage';
45 - import { onMounted, ref } from 'vue'; 49 + import { onMounted, ref, computed } from 'vue';
46 import { useDrawer } from '/@/components/Drawer'; 50 import { useDrawer } from '/@/components/Drawer';
47 import FinanceEdit from './FinanceEdit.vue'; 51 import FinanceEdit from './FinanceEdit.vue';
48 import CheckDetail from './CheckDetail.vue'; 52 import CheckDetail from './CheckDetail.vue';
  53 + import HistoryDetail from './HistoryDetail.vue';
49 import { useOrderStoreWithOut } from '/@/store/modules/order'; 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 const { createMessage } = useMessage(); 59 const { createMessage } = useMessage();
52 const { error } = createMessage; 60 const { error } = createMessage;
@@ -54,6 +62,12 @@ @@ -54,6 +62,12 @@
54 const orderStore = useOrderStoreWithOut(); 62 const orderStore = useOrderStoreWithOut();
55 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer(); 63 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
56 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); 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 const handleOk = (record) => { 71 const handleOk = (record) => {
58 // 修改父组件的状态 72 // 修改父组件的状态
59 closeModal(); 73 closeModal();
@@ -81,7 +95,7 @@ @@ -81,7 +95,7 @@
81 setting: false, 95 setting: false,
82 }, 96 },
83 actionColumn: { 97 actionColumn: {
84 - width: 240, 98 + width: 260,
85 title: 'Action', 99 title: 'Action',
86 dataIndex: 'action', 100 dataIndex: 'action',
87 }, 101 },
@@ -113,6 +127,18 @@ @@ -113,6 +127,18 @@
113 // }, 127 // },
114 onClick: handleFalse.bind(null, record), 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 return [ 144 return [
@@ -130,6 +156,18 @@ @@ -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 onMounted(async () => { 171 onMounted(async () => {
134 await orderStore.getDict(); 172 await orderStore.getDict();
135 }); 173 });
@@ -173,5 +211,25 @@ @@ -173,5 +211,25 @@
173 reload(); 211 reload();
174 }, 50); 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 </script> 234 </script>
177 <style></style> 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,4 +187,18 @@ export const COLUMNS = [
187 return column.record?.packetProfitRate?.toFixed(2); 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 \ No newline at end of file 205 \ No newline at end of file
src/views/project/finance/financeProfit/ServiceProfit/PackageProfit/index.vue
@@ -6,7 +6,10 @@ @@ -6,7 +6,10 @@
6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" /> 6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 </template> 7 </template>
8 <template v-if="column.key === 'action'"> 8 <template v-if="column.key === 'action'">
9 - <TableAction :actions="createActions(record)" /> 9 + <TableAction
  10 + :actions="createActions(record)"
  11 + :dropDownActions="createDropActions(record)"
  12 + />
10 </template> 13 </template>
11 <!-- <template v-if="column.key === 'relationValue'"> 14 <!-- <template v-if="column.key === 'relationValue'">
12 <a-input 15 <a-input
@@ -34,6 +37,7 @@ @@ -34,6 +37,7 @@
34 </BasicModal> --> 37 </BasicModal> -->
35 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" /> 38 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> 39 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  40 + <HistoryDetail @register="registerHistoryDetail" />
37 </div> 41 </div>
38 </template> 42 </template>
39 <script setup lang="ts"> 43 <script setup lang="ts">
@@ -42,12 +46,16 @@ @@ -42,12 +46,16 @@
42 import { searchFormSchema, COLUMNS } from './data'; 46 import { searchFormSchema, COLUMNS } from './data';
43 import { BasicModal, useModal } from '/@/components/Modal'; 47 import { BasicModal, useModal } from '/@/components/Modal';
44 import { useMessage } from '/@/hooks/web/useMessage'; 48 import { useMessage } from '/@/hooks/web/useMessage';
45 - import { onMounted, ref } from 'vue'; 49 + import { onMounted, ref, computed } from 'vue';
46 import { useDrawer } from '/@/components/Drawer'; 50 import { useDrawer } from '/@/components/Drawer';
47 import FinanceEdit from './FinanceEdit.vue'; 51 import FinanceEdit from './FinanceEdit.vue';
48 import CheckDetail from './CheckDetail.vue'; 52 import CheckDetail from './CheckDetail.vue';
  53 + import HistoryDetail from './HistoryDetail.vue';
49 import { FilePptOutlined } from '@ant-design/icons-vue'; 54 import { FilePptOutlined } from '@ant-design/icons-vue';
50 import { useOrderStoreWithOut } from '/@/store/modules/order'; 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 const { createMessage } = useMessage(); 60 const { createMessage } = useMessage();
53 const { error } = createMessage; 61 const { error } = createMessage;
@@ -55,6 +63,12 @@ @@ -55,6 +63,12 @@
55 const orderStore = useOrderStoreWithOut(); 63 const orderStore = useOrderStoreWithOut();
56 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer(); 64 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
57 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); 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 const handleOk = (record) => { 72 const handleOk = (record) => {
59 // 修改父组件的状态 73 // 修改父组件的状态
60 closeModal(); 74 closeModal();
@@ -81,7 +95,7 @@ @@ -81,7 +95,7 @@
81 setting: false, 95 setting: false,
82 }, 96 },
83 actionColumn: { 97 actionColumn: {
84 - width: 240, 98 + width: 260,
85 title: 'Action', 99 title: 'Action',
86 dataIndex: 'action', 100 dataIndex: 'action',
87 }, 101 },
@@ -113,6 +127,18 @@ @@ -113,6 +127,18 @@
113 // }, 127 // },
114 onClick: handleFalse.bind(null, record), 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 return [ 144 return [
@@ -130,9 +156,17 @@ @@ -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 function handleFinanceEdit(record) { 171 function handleFinanceEdit(record) {
138 openFinanceEdit(true, { 172 openFinanceEdit(true, {
@@ -176,5 +210,29 @@ @@ -176,5 +210,29 @@
176 // await deleteConfig({ ids: [record.id] }); 210 // await deleteConfig({ ids: [record.id] });
177 // reload(); 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 </script> 237 </script>
180 <style></style> 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,7 +140,6 @@ export const COLUMNS = [
140 dataIndex: 'packetTotalPrice', 140 dataIndex: 'packetTotalPrice',
141 width: 150, 141 width: 150,
142 customRender: (column) => { 142 customRender: (column) => {
143 - console.log(column, '5656666666');  
144 return column.record?.packetRmbTotalPrice?.toFixed(2); 143 return column.record?.packetRmbTotalPrice?.toFixed(2);
145 }, 144 },
146 }, 145 },
@@ -311,14 +310,6 @@ export const COLUMNS = [ @@ -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 title: '综合收益¥', 313 title: '综合收益¥',
323 dataIndex: 'comprehensiveProfit', 314 dataIndex: 'comprehensiveProfit',
324 width: 120, 315 width: 120,
@@ -381,4 +372,18 @@ export const COLUMNS = [ @@ -381,4 +372,18 @@ export const COLUMNS = [
381 return <FilePptOutlined style="font-size:25px" onClick={() => handleClick()} />; 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 \ No newline at end of file 390 \ No newline at end of file
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/index.vue
@@ -3,7 +3,10 @@ @@ -3,7 +3,10 @@
3 <BasicTable @register="registerTable" :bordered="true"> 3 <BasicTable @register="registerTable" :bordered="true">
4 <template #bodyCell="{ column, record }"> 4 <template #bodyCell="{ column, record }">
5 <template v-if="column.key === 'action'"> 5 <template v-if="column.key === 'action'">
6 - <TableAction :actions="createActions(record)" /> 6 + <TableAction
  7 + :actions="createActions(record)"
  8 + :dropDownActions="createDropActions(record)"
  9 + />
7 </template> 10 </template>
8 <!-- <template v-if="column.key === 'relationValue'"> 11 <!-- <template v-if="column.key === 'relationValue'">
9 <a-input 12 <a-input
@@ -31,32 +34,39 @@ @@ -31,32 +34,39 @@
31 </BasicModal> --> 34 </BasicModal> -->
32 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" /> 35 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
33 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> 36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  37 + <HistoryDetail @register="registerHistoryDetail" />
34 </div> 38 </div>
35 </template> 39 </template>
36 <script setup lang="ts"> 40 <script setup lang="ts">
37 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 41 import { BasicTable, useTable, TableAction } from '/@/components/Table';
38 import { getServiceProfit } from '@/api/project/invoice'; 42 import { getServiceProfit } from '@/api/project/invoice';
39 import { searchFormSchema, COLUMNS } from './data'; 43 import { searchFormSchema, COLUMNS } from './data';
40 - import { BasicModal, useModal } from '/@/components/Modal';  
41 import { useMessage } from '/@/hooks/web/useMessage'; 44 import { useMessage } from '/@/hooks/web/useMessage';
42 - import { onMounted, ref } from 'vue'; 45 + import { onMounted, ref, computed, unref } from 'vue';
43 import { useDrawer } from '/@/components/Drawer'; 46 import { useDrawer } from '/@/components/Drawer';
44 import FinanceEdit from './FinanceEdit.vue'; 47 import FinanceEdit from './FinanceEdit.vue';
  48 + import HistoryDetail from './HistoryDetail.vue';
45 import CheckDetail from './CheckDetail.vue'; 49 import CheckDetail from './CheckDetail.vue';
  50 + import { useUserStoreWithOut } from '/@/store/modules/user';
  51 + import { ROLE } from '../../../type.d';
46 import { useOrderStoreWithOut } from '/@/store/modules/order'; 52 import { useOrderStoreWithOut } from '/@/store/modules/order';
47 53
48 const { createMessage } = useMessage(); 54 const { createMessage } = useMessage();
49 - const { error } = createMessage;  
50 const message = ref(); 55 const message = ref();
  56 + const checkedKeys = ref<string[]>([]);
  57 + const invoiceIdKeys = ref<string[]>([]);
  58 + const checkIdKeys = ref<string[]>([]);
51 const orderStore = useOrderStoreWithOut(); 59 const orderStore = useOrderStoreWithOut();
52 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer(); 60 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
53 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); 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 api: getServiceProfit, 70 api: getServiceProfit,
61 bordered: true, 71 bordered: true,
62 columns: COLUMNS, 72 columns: COLUMNS,
@@ -74,7 +84,7 @@ @@ -74,7 +84,7 @@
74 setting: false, 84 setting: false,
75 }, 85 },
76 actionColumn: { 86 actionColumn: {
77 - width: 240, 87 + width: 260,
78 title: 'Action', 88 title: 'Action',
79 dataIndex: 'action', 89 dataIndex: 'action',
80 }, 90 },
@@ -82,7 +92,7 @@ @@ -82,7 +92,7 @@
82 92
83 function createActions(record: any): any[] { 93 function createActions(record: any): any[] {
84 if (!record.editable) { 94 if (!record.editable) {
85 - return [ 95 + const actions = [
86 { 96 {
87 label: '财务编辑', 97 label: '财务编辑',
88 onClick: handleFinanceEdit.bind(null, record), 98 onClick: handleFinanceEdit.bind(null, record),
@@ -106,7 +116,20 @@ @@ -106,7 +116,20 @@
106 // }, 116 // },
107 onClick: handleFalse.bind(null, record), 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 return [ 134 return [
112 { 135 {
@@ -122,6 +145,17 @@ @@ -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 onMounted(async () => { 160 onMounted(async () => {
127 await orderStore.getDict(); 161 await orderStore.getDict();
@@ -160,7 +194,6 @@ @@ -160,7 +194,6 @@
160 // error('请勿连续点击生成按钮,需要等待三秒再点击生成'); 194 // error('请勿连续点击生成按钮,需要等待三秒再点击生成');
161 // } else { 195 // } else {
162 record.onEdit?.(true); 196 record.onEdit?.(true);
163 - // }  
164 } 197 }
165 198
166 function handleCancel(record) { 199 function handleCancel(record) {
@@ -171,5 +204,21 @@ @@ -171,5 +204,21 @@
171 // await deleteConfig({ ids: [record.id] }); 204 // await deleteConfig({ ids: [record.id] });
172 reload(); 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 </script> 223 </script>
175 <style></style> 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 +}