ccef2b613fe21a6be5f2096f88a2de5eb301adde..d5ca5d8855aa27f770e824a8f7159aedb239614d
6 天以前 gaoluyang
1.质量管理-附件分页bug修改
d5ca5d 对比 | 目录
6 天以前 gaoluyang
1.质量管理-附件分页bug修改
e9a81d 对比 | 目录
6 天以前 gaoluyang
Merge remote-tracking branch 'origin/dev' into dev
787dde 对比 | 目录
6 天以前 gaoluyang
1.协同审批流程联调
76ebf7 对比 | 目录
6 天以前 spring
过程检验、出厂检验编辑页面字段改下(检测结果项建议必填,不输入检测结果会展示空框)
2ab68f 对比 | 目录
6 天以前 spring
采购台账上传超过10M大小的文件时,提示语多了一条
57e9a9 对比 | 目录
6 天以前 spring
Merge remote-tracking branch 'origin/dev' into dev
fd3e3b 对比 | 目录
6 天以前 spring
添加新增离职时,页面新增入职字段改为新增离职。员工编号改为下拉选择框,选择员工编号后带出人员入职填的信息
b114f4 对比 | 目录
6 天以前 gaoluyang
1.来票登记-不要删除和导出
46a976 对比 | 目录
6 天以前 gaoluyang
1.来票登记-新增登记计算报错,关闭弹框后没有刷新列表问题
d90576 对比 | 目录
6 天以前 gaoluyang
1.采购台账-销售台账:金额都可以填写,填一个计算另外一个
e09387 对比 | 目录
6 天以前 gaoluyang
1.采购管理-来票登记,编辑试本次来票金额也可以填写,互相计算
60916e 对比 | 目录
6 天以前 gaoluyang
Merge remote-tracking branch 'origin/dev' into dev
02c720 对比 | 目录
6 天以前 gaoluyang
1.采购管理-来票登记的登记弹框表格加合计,小数点两位
678428 对比 | 目录
6 天以前 spring
Merge remote-tracking branch 'origin/dev' into dev
5709db 对比 | 目录
6 天以前 spring
修改芯导logo
b7b0e7 对比 | 目录
6 天以前 gaoluyang
1.销售管理、采购管理优化
74ef34 对比 | 目录
已修改31个文件
1081 ■■■■ 文件已修改
src/api/personnelManagement/onboarding.js 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/qualityManagement/qualityInspectFile.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/芯导软件(江苏)有限公司.png 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue 238 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/dimission/components/formDia.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/components/ExpandTable.vue 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/components/Modal.vue 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/index.vue 75 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/indexOld.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentEntry/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentHistory/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentLedger/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/Form/EditForm.vue 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/index.vue 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 107 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/filesDia.vue 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/formDia.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/filesDia.vue 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/formDia.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/filesDia.vue 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceLedger/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceRegistration/index.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPayment/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentHistory/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentLedger/index.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue 189 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/personnelManagement/onboarding.js
@@ -1,42 +1,49 @@
import request from '@/utils/request'
import request from "@/utils/request";
// æŸ¥è¯¢äººå‘˜å…¥èŒåˆ—表
export function staffJoinListPage(query) {
    return request({
        url: '/staff/staffJoinLeaveRecord/listPage',
        method: 'get',
        params: query,
    })
  return request({
    url: "/staff/staffJoinLeaveRecord/listPage",
    method: "get",
    params: query,
  });
}
// æ–°å¢žäººå‘˜å…¥èŒ
export function staffJoinAdd(query) {
    return request({
        url: '/staff/staffJoinLeaveRecord/add',
        method: 'post',
        data: query,
    })
  return request({
    url: "/staff/staffJoinLeaveRecord/add",
    method: "post",
    data: query,
  });
}
// ä¿®æ”¹äººå‘˜å…¥èŒ
export function staffJoinUpdate(query) {
    return request({
        url: '/staff/staffJoinLeaveRecord/update',
        method: 'post',
        data: query,
    })
  return request({
    url: "/staff/staffJoinLeaveRecord/update",
    method: "post",
    data: query,
  });
}
// æŸ¥è¯¢å‘˜å·¥å…¥èŒä¿¡æ¯
export function getStaffJoinInfo(query) {
    return request({
        url: '/staff/staffJoinLeaveRecord/' + query,
        method: 'get',
        data: query,
    })
  return request({
    url: "/staff/staffJoinLeaveRecord/" + query,
    method: "get",
    data: query,
  });
}
// åˆ é™¤å‘˜å·¥
export function staffJoinDel(query) {
    return request({
        url: '/staff/staffJoinLeaveRecord/del',
        method: 'delete',
        data: query,
    })
}
  return request({
    url: "/staff/staffJoinLeaveRecord/del",
    method: "delete",
    data: query,
  });
}
export function getStaffOnJob() {
  return request({
    url: "/staff/staffOnJob/list",
    method: "get",
  });
}
src/api/qualityManagement/qualityInspectFile.js
@@ -8,7 +8,7 @@
        params: query,
    })
}
// æŸ¥è¯¢é™„件列表
// ä¿å­˜é™„件列表
export function qualityInspectFileAdd(query) {
    return request({
        url: '/quality/qualityInspectFile/add',
@@ -16,7 +16,7 @@
        data: query,
    })
}
// æŸ¥è¯¢é™„件列表
// åˆ é™¤é™„件列表
export function qualityInspectFileDel(query) {
    return request({
        url: '/quality/qualityInspectFile/del',
src/assets/logo/оµ¼Èí¼þ£¨½­ËÕ£©ÓÐÏÞ¹«Ë¾.png

src/store/modules/user.js
@@ -52,7 +52,7 @@
            this.avatar = avatar
            this.currentFactoryName = user.currentFactoryName
            this.nickName = user.nickName
            this.currentDeptId = user.currentDeptId
            this.currentDeptId = user.tenantId
            resolve(res)
          }).catch(error => {
            reject(error)
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
@@ -1,41 +1,118 @@
<template>
  <div>
    <el-dialog
        v-model="dialogFormVisible"
        :title="operationType === 'add' ? '新增审批流程' : '编辑审批流程'"
        width="700px"
        @close="closeDia"
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增审批流程' : '编辑审批流程'"
      width="700px"
      @close="closeDia"
    >
            <el-form :model="form" label-width="140px" label-position="top" ref="formRef">
                <el-row>
                    <el-col :span="24">
                        <el-form-item label="流程编号:" prop="approveId">
                            <el-input v-model="form.approveId" placeholder="自动编号" clearable disabled/>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="24">
                        <el-form-item label="申请部门:" prop="approveDeptId">
                            <el-select
                                disabled
                                v-model="form.approveDeptId"
                                placeholder="选择部门"
                            >
                                <el-option
                                    v-for="user in productOptions"
                                    :key="user.deptId"
                                    :label="user.deptName"
                                    :value="user.deptId"
                                />
                            </el-select>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="24">
                        <el-form-item label="审批事由:" prop="approveReason">
                            <el-input v-model="form.approveReason" placeholder="请输入" clearable type="textarea" disabled/>
                        </el-form-item>
                    </el-col>
                </el-row>
                <!-- å®¡æ‰¹äººé€‰æ‹©ï¼ˆåŠ¨æ€èŠ‚ç‚¹ï¼‰ -->
                <el-row :gutter="30">
                    <el-col :span="12">
                        <el-form-item label="申请人:" prop="approveUser">
                            <el-select
                                v-model="form.approveUser"
                                placeholder="选择人员"
                                disabled
                            >
                                <el-option
                                    v-for="user in userList"
                                    :key="user.userId"
                                    :label="user.nickName"
                                    :value="user.userId"
                                />
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="申请日期:" prop="approveTime">
                            <el-date-picker
                                v-model="form.approveTime"
                                type="date"
                                placeholder="请选择日期"
                                value-format="YYYY-MM-DD"
                                format="YYYY-MM-DD"
                                clearable
                                style="width: 100%"
                                disabled
                            />
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
      <el-form :model="{ activities }" ref="formRef" label-position="top">
        <el-timeline style="max-width: 600px">
          <el-timeline-item
              v-for="(activity, index) in activities"
              :key="index"
              :type="activity.current ? 'primary' : ''"
              :hollow="activity.current"
              :timestamp="activity.approveNodeTime"
        <el-steps :active="getActiveStep()" finish-status="success" process-status="process" align-center direction="vertical">
          <el-step
            v-for="(activity, index) in activities"
            :key="index"
                        finish-status="success"
            :title="getNodeTitle(index, activities.length)"
            :description="activity.approveNodeUser"
            :icon="getNodeIcon(activity, index)"
          >
            <el-card>
              <span style="font-size: 18px;font-weight: 700">节点{{activity.approveNodeOrder}}</span>
              <div style="margin: 10px 0">
                <span style="font-size: 16px;font-weight: 600">审批人:{{activity.approveNodeUser}}</span>
                        <template #icon>
                            <el-icon v-if="activity.approveNodeStatus === 2" color="red" :size="22"><WarningFilled /></el-icon>
                            <el-icon v-else-if="activity.isShen" color="#1890ff" :size="22"><Edit /></el-icon>
                            <el-icon v-else-if="activity.approveNodeStatus === 1" color="#67C23A" :size="26"><Check /></el-icon>
                            <el-icon v-else color="#C0C4CC" :size="22"><MoreFilled /></el-icon>
                        </template>
            <template #title>
              <span style="color: #000000">{{ getNodeTitle(index, activities.length) }}</span>
            </template>
            <template #description>
              <div class="node-user">
                <div class="avatar-wrapper">
                  <img :src="userStore.avatar" class="user-avatar" alt=""/>
                </div>
                <span style="color: #000000">{{ activity.approveNodeUser }}-{{activity.isApproval}}</span>
              </div>
              <div>
                <span style="margin-bottom: 8px;display: inline-block;font-size: 16px;font-weight: 600">审批意见:</span>
              <div v-if="!activity.isShen" class="node-reason">
                <span>审批意见:</span>{{ activity.approveNodeReason }}
              </div>
              <div v-else-if="activity.isShen">
                <el-form-item
                  v-if="activity.approveNodeRemark == 1"
                  :prop="'activities.' + index + '.approveNodeReason'"
                  :rules="[{ required: true, message: '审批意见不能为空', trigger: 'blur' }]"
                >
                  <el-input v-model="activity.approveNodeReason" clearable type="textarea" :disabled="operationType === 'view'"></el-input>
                </el-form-item>
                <el-form-item v-else>
                  <el-input v-model="activity.approveNodeReason" clearable type="textarea" disabled></el-input>
                </el-form-item>
              </div>
            </el-card>
          </el-timeline-item>
        </el-timeline>
            </template>
          </el-step>
        </el-steps>
      </el-form>
      <template #footer v-if="operationType === 'approval'">
        <div class="dialog-footer">
@@ -49,8 +126,15 @@
</template>
<script setup>
import {getCurrentInstance, ref} from "vue";
import {approveProcessDetails, updateApproveNode} from "../../../../api/collaborativeApproval/approvalProcess.js";
import {getCurrentInstance, reactive, ref, toRefs} from "vue";
import {
    approveProcessDetails,
    getDept,
    updateApproveNode
} from "@/api/collaborativeApproval/approvalProcess.js";
import useUserStore from "@/store/modules/user.js";
import {userListNoPageByTenantId} from "@/api/system/user.js";
import { WarningFilled, Edit, Check, MoreFilled } from '@element-plus/icons-vue'
const emit = defineEmits(['close'])
const { proxy } = getCurrentInstance()
@@ -58,24 +142,80 @@
const operationType = ref('')
const activities = ref([])
const formRef = ref(null);
const userStore = useUserStore()
const productOptions = ref([]);
const userList = ref([])
const data = reactive({
    form: {
        approveTime: "",
        approveId: "",
        approveUser: "",
        approveDeptId: "",
        approveReason: "",
        checkResult: "",
    },
});
const { form } = toRefs(data);
// èŠ‚ç‚¹æ ‡é¢˜
const getNodeTitle = (index, len) => {
  if (index === 0) return '发起';
  if (index === len - 1) return '结束';
  return '审批';
};
// èŽ·å–å½“å‰æ¿€æ´»æ­¥éª¤
const getActiveStep = () => {
  // å¦‚果所有 isShen éƒ½ä¸º false,返回最后一个步骤(全部完成)
  const hasActive = activities.value.some(a => a.isShen === true);
  if (!hasActive) return activities.value.length;
  // å½“前节点索引
  return activities.value.findIndex(a => a.isShen  == true);
};
// æ­¥éª¤icon
const getNodeIcon = (activity, index) => {
  if (activity.approveNodeStatus === 2) return 'el-icon-warning'; // ä¸é€šè¿‡
  if (activity.isShen) return 'Edit';
  return '';
};
// æ‰“开弹框
const openDialog = (type, row) => {
  operationType.value = type;
  dialogFormVisible.value = true;
    approveProcessDetails(row.approveId).then((res) => {
        console.log(res)
        activities.value = res.data
    })
    userListNoPageByTenantId().then((res) => {
        userList.value = res.data;
    });
    form.value = {...row}
    getProductOptions()
  approveProcessDetails(row.approveId).then((res) => {
    activities.value = res.data
    // å¢žåŠ isApproval字段
    activities.value.forEach(item => {
      if (item.approveNodeStatus === 2) {
        item.isApproval = '已驳回';
      } else if (item.approveNodeStatus === 1) {
        item.isApproval = '已同意';
      } else {
        item.isApproval = '未审批';
      }
    })
  })
}
const getProductOptions = () => {
    getDept().then((res) => {
        productOptions.value = res.data;
    });
};
// æäº¤å®¡æ‰¹
const submitForm = (status) => {
    const filteredActivities = activities.value.filter(activity => activity.approveNodeRemark == 1);
    filteredActivities[0].approveNodeStatus = status
    updateApproveNode(filteredActivities[0]).then(() => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
    })
  const filteredActivities = activities.value.filter(activity => activity.isShen);
  filteredActivities[0].approveNodeStatus = status
  // åˆ¤æ–­æ˜¯å¦ä¸ºæœ€åŽä¸€æ­¥
  const isLast = activities.value.findIndex(a => a.isShen) === activities.value.length-1;
  updateApproveNode({ ...filteredActivities[0], isLast }).then(() => {
    proxy.$modal.msgSuccess("提交成功");
    closeDia();
  })
}
// å…³é—­å¼¹æ¡†
const closeDia = () => {
@@ -89,7 +229,29 @@
</script>
<style scoped>
.el-timeline {
  padding-left: 10px;
.node-user {
  margin: 10px 0;
  font-size: 16px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 8px;
}
.node-status {
  color: #1890ff;
  margin-left: 8px;
  font-size: 14px;
}
.node-reason {
  font-size: 15px;
  color: #333;
  margin: 10px 0;
}
.user-avatar {
    cursor: pointer;
    width: 30px;
    height: 30px;
    border-radius: 50px;
}
</style>
src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
@@ -53,7 +53,11 @@
                  :key="node.id"
                  style="margin-right: 30px; text-align: center; margin-bottom: 10px;"
                >
                  <div>节点{{ index + 1 }} â†’</div>
                  <div>
                    <span v-if="index === 0">发起</span>
                    <span v-else>审批</span>
                    â†’
                  </div>
                  <el-select
                    v-model="node.userId"
                    placeholder="选择人员"
@@ -126,8 +130,8 @@
  approveProcessAdd, approveProcessGetInfo,
  approveProcessUpdate,
  getDept
} from "../../../../api/collaborativeApproval/approvalProcess.js";
import {userListNoPage, getUserProfile} from "../../../../api/system/user.js";
} from "@/api/collaborativeApproval/approvalProcess.js";
import {userListNoPageByTenantId} from "@/api/system/user.js";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
import useUserStore from "@/store/modules/user";
@@ -156,6 +160,7 @@
});
const { form, rules } = toRefs(data);
const productOptions = ref([]);
const currentApproveStatus = ref(0)
// å®¡æ‰¹äººèŠ‚ç‚¹ç›¸å…³
const approverNodes = ref([
@@ -174,7 +179,8 @@
const openDialog = (type, row) => {
  operationType.value = type;
  dialogFormVisible.value = true;
  userListNoPage().then((res) => {
    currentApproveStatus.value = row.approveStatus
    userListNoPageByTenantId().then((res) => {
    userList.value = res.data;
  });
  getProductOptions();
@@ -236,7 +242,7 @@
  }
  proxy.$refs.formRef.validate(valid => {
    if (valid) {
      if (operationType.value === "add") {
      if (operationType.value === "add" || currentApproveStatus.value == 3) {
        approveProcessAdd(form.value).then(res => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
src/views/collaborativeApproval/approvalProcess/index.vue
@@ -45,9 +45,10 @@
import {ElMessageBox} from "element-plus";
import InfoFormDia from "@/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue";
import ApprovalDia from "@/views/collaborativeApproval/approvalProcess/components/approvalDia.vue";
import {approveProcessDelete, approveProcessListPage} from "../../../api/collaborativeApproval/approvalProcess.js";
import {approveProcessDelete, approveProcessListPage} from "@/api/collaborativeApproval/approvalProcess.js";
import useUserStore from "@/store/modules/user";
const userStore = useUserStore();
const data = reactive({
  searchForm: {
@@ -139,7 +140,7 @@
        clickFun: (row) => {
          openApprovalDia("approval", row);
        },
                disabled: (row) => row.approveUserCurrentId == null || row.approveStatus == 2
                disabled: (row) => row.approveUserCurrentId == null || row.approveStatus == 2 || row.approveStatus == 3 || row.approveUserCurrentId !== userStore.id
      },
      {
        name: "详情",
src/views/personnelManagement/dimission/components/formDia.vue
@@ -2,20 +2,28 @@
  <div>
    <el-dialog
        v-model="dialogFormVisible"
        :title="operationType === 'add' ? '新增入职' : '编辑人员'"
        :title="operationType === 'add' ? '新增离职' : '编辑离职'"
        width="70%"
        @close="closeDia"
    >
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="员工编号:" prop="staffNo">
              <el-input v-model="form.staffNo" placeholder="请输入" clearable :disabled="operationType !== 'add'"/>
            <el-form-item label="姓名:" prop="staffName">
              <!-- <el-input v-model="form.staffName" placeholder="请输入" clearable/> -->
              <el-select v-model="form.staffName" placeholder="请选择人员" style="width: 100%" @change="handleSelect">
              <el-option
                v-for="item in personList"
                :key="item.id"
                :label="item.staffName"
                :value="item.staffName"
              />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="姓名:" prop="staffName">
              <el-input v-model="form.staffName" placeholder="请输入" clearable/>
            <el-form-item label="员工编号:" prop="staffNo">
              <el-input v-model="form.staffNo" placeholder="请输入" clearable :disabled="operationType !== 'add'"/>
            </el-form-item>
          </el-col>
        </el-row>
@@ -135,7 +143,7 @@
<script setup>
import {ref} from "vue";
import {getStaffJoinInfo, staffJoinAdd, staffJoinUpdate} from "@/api/personnelManagement/onboarding.js";
import {getStaffJoinInfo, staffJoinAdd, staffJoinUpdate,getStaffOnJob} from "@/api/personnelManagement/onboarding.js";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
@@ -184,6 +192,7 @@
// æ‰“开弹框
const openDialog = (type, row) => {
  getList()
  operationType.value = type;
  dialogFormVisible.value = true;
  if (operationType.value === 'edit') {
@@ -217,6 +226,58 @@
  dialogFormVisible.value = false;
  emit('close')
};
const personList = ref([]);
/**
 * èŽ·å–å½“å‰åœ¨èŒäººå‘˜åˆ—è¡¨
 */
const getList = () => {
  getStaffOnJob().then(res => {
    personList.value = res.data
  })
};
const handleSelect = (val) => {
  let obj = personList.value.find(item => item.staffName === val)
  let {
    sex,
    phone,
    staffNo,
    nativePlace,
    postJob,
    adress,
    firstStudy,
    profession,
    identityCard,
    age,
    emergencyContact,
    emergencyContactPhone,
    contractTerm,
    contractStartTime,
    contractEndTime,
    staffName
  } = obj
  form.value = {
    sex,
    phone,
    staffNo,
    nativePlace,
    postJob,
    adress,
    firstStudy,
    profession,
    identityCard,
    age,
    emergencyContact,
    emergencyContactPhone,
    contractTerm,
    contractStartTime,
    contractEndTime,
    staffName
  }
}
defineExpose({
  openDialog,
});
src/views/procurementManagement/invoiceEntry/components/ExpandTable.vue
@@ -4,6 +4,8 @@
    :column="columns"
    :tableData="dataList"
    :tableLoading="loading"
        :summaryMethod="summarizeChildrenTable"
        :isShowSummary="true"
    height="auto"
  >
  </PIMTable>
@@ -13,6 +15,7 @@
import { usePaginationApi } from "@/hooks/usePaginationApi";
import { productList } from "@/api/procurementManagement/procurementLedger.js";
import { nextTick } from "vue";
const { proxy } = getCurrentInstance();
defineOptions({
  name: "来票登记折叠表",
@@ -56,6 +59,7 @@
    {
      label: "含税单价(元)",
      prop: "taxInclusiveUnitPrice",
            width:200,
      formatData: (val) => {
        return val ? parseFloat(val).toFixed(2) : "-";
      },
@@ -63,6 +67,7 @@
    {
      label: "含税总价(元)",
      prop: "taxInclusiveTotalPrice",
            width:200,
      formatData: (val) => {
        return val ? parseFloat(val).toFixed(2) : "-";
      },
@@ -70,6 +75,7 @@
    {
      label: "不含税总价(元)",
      prop: "taxExclusiveTotalPrice",
            width:200,
      formatData: (val) => {
        return val ? parseFloat(val).toFixed(2) : "-";
      },
@@ -77,6 +83,7 @@
    {
      label: "本次来票金额(元)",
      prop: "ticketsAmount",
            width:200,
      formatData: (val) => {
        return val ? parseFloat(val).toFixed(2) : "-";
      },
@@ -88,6 +95,7 @@
    {
      label: "未来票金额(元)",
      prop: "futureTicketsAmount",
            width:200,
      formatData: (val) => {
        return val ? parseFloat(val).toFixed(2) : "-";
      },
@@ -105,7 +113,25 @@
  filters.salesLedgerId = id;
  getTableData();
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
    return proxy.summarizeTable(
        param,
        [
            "taxInclusiveUnitPrice",
            "taxInclusiveTotalPrice",
            "taxExclusiveTotalPrice",
            "ticketsNum",
            "ticketsAmount",
            "futureTickets",
            "futureTicketsAmount",
        ],
        {
            ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
            futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
        }
    );
};
defineExpose({
  getList,
});
src/views/procurementManagement/invoiceEntry/components/Modal.vue
@@ -113,12 +113,14 @@
        rowKey="id"
        :column="columns"
        :tableData="form.productData"
                :summaryMethod="summarizeChildrenTable"
                :isShowSummary="true"
        height="auto"
      >
        <template #ticketsNumRef="{ row }">
          <el-input-number
            v-model="row.ticketsNum"
            placeholder="请选择"
            placeholder="请输入"
            :min="0"
            :step="0.1"
            clearable
@@ -129,7 +131,7 @@
        <template #ticketsAmountRef="{ row }">
          <el-input-number
            v-model="row.ticketsAmount"
            placeholder="请选择"
            placeholder="请输入"
            :min="0"
            :step="0.1"
            clearable
@@ -150,6 +152,7 @@
<script setup>
import { ref, getCurrentInstance } from "vue";
import { defineEmits } from 'vue';
import { useModal } from "@/hooks/useModal";
import useFormData from "@/hooks/useFormData";
import FileUpload from "@/components/Upload/FileUpload.vue";
@@ -210,6 +213,8 @@
} = useModal({
  title: "来票登记",
});
const emit = defineEmits(['refreshList']);
const columns = [
  {
@@ -283,10 +288,12 @@
  {
    label: "未来票数",
    prop: "futureTickets",
        width: 100,
  },
  {
    label: "未来票金额(元)",
    prop: "futureTicketsAmount",
        width: 200,
  },
];
@@ -316,7 +323,19 @@
    form.productData = data.productData;
  }
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
    return proxy.summarizeTable(param, [
        "taxInclusiveUnitPrice",
        "taxInclusiveTotalPrice",
        "taxExclusiveTotalPrice",
        "ticketsNum",
        "ticketsAmount",
        "ticketsAmountRef",
        "futureTickets",
        "futureTicketsAmount",
    ]);
};
//本次来票数失焦操作
const invoiceNumBlur = (row) => {
  if (!row.ticketsNum || row.ticketsNum === "") {
@@ -328,11 +347,11 @@
    return;
  }
  // è®¡ç®—本次来票金额
  row.ticketsAmount = row.ticketsNum * row.taxInclusiveUnitPrice;
  row.ticketsAmount = (row.ticketsNum * row.taxInclusiveUnitPrice).toFixed(2)
  // è®¡ç®—未来票数
  row.futureTickets = row.tempFutureTickets - row.ticketsNum;
  row.futureTickets = (row.tempFutureTickets - row.ticketsNum).toFixed(2)
  // è®¡ç®—未来票金额
  row.futureTicketsAmount = row.tempFutureTicketsAmount - row.ticketsAmount;
  row.futureTicketsAmount = (row.tempFutureTicketsAmount - row.ticketsAmount).toFixed(2)
  calculateinvoiceAmount();
};
@@ -351,9 +370,9 @@
    (row.ticketsAmount / row.taxInclusiveUnitPrice).toFixed(2)
  );
  // è®¡ç®—未来票数
  row.futureTickets = row.tempFutureTickets - row.ticketsNum;
  row.futureTickets = (row.tempFutureTickets - row.ticketsNum).toFixed(2)
  // è®¡ç®—未来票金额
  row.futureTicketsAmount = row.tempFutureTicketsAmount - row.ticketsAmount;
  row.futureTicketsAmount = (row.tempFutureTicketsAmount - row.ticketsAmount).toFixed(2)
  calculateinvoiceAmount();
};
@@ -361,7 +380,7 @@
  let invoiceAmountTotal = 0;
  form.productData.forEach((item) => {
    if (item.ticketsAmount) {
      invoiceAmountTotal += item.ticketsAmount;
      invoiceAmountTotal += Number(item.ticketsAmount);
    }
  });
  form.invoiceAmount = invoiceAmountTotal.toFixed(2);
@@ -381,6 +400,11 @@
const removeFile = (file) => {
  const { tempId } = file.response.data;
  form.tempFileIds = form.tempFileIds.filter((item) => item !== tempId);
};
const closeAndRefresh = () => {
  closeModal();
  emit('refreshList');
};
const submitForm = () => {
@@ -406,7 +430,7 @@
      });
      modalLoading.value = false;
      if (code == 200) {
        closeModal();
        closeAndRefresh();
      }
    } else {
      modalLoading.value = false;
@@ -416,6 +440,7 @@
defineExpose({
  open,
  closeAndRefresh,
});
</script>
src/views/procurementManagement/invoiceEntry/index.vue
@@ -40,6 +40,8 @@
          total: pagination.total,
        }"
        :expand-row-keys="expandRowKeys"
        :summaryMethod="summarizeMainTable"
        :isShowSummary="true"
        @expand-change="expandChange"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
@@ -59,16 +61,17 @@
        </template>
      </PIMTable>
    </div>
    <Modal ref="modalRef"></Modal>
    <Modal ref="modalRef" @refreshList="getTableData"></Modal>
  </div>
</template>
<script setup>
import { usePaginationApi } from "@/hooks/usePaginationApi";
import { gePurchaseListPage } from "@/api/procurementManagement/invoiceEntry.js";
import {delRegistration, gePurchaseListPage} from "@/api/procurementManagement/invoiceEntry.js";
import { nextTick, onMounted, getCurrentInstance } from "vue";
import ExpandTable from "./components/ExpandTable.vue";
import Modal from "./components/Modal.vue";
import {ElMessageBox} from "element-plus";
defineOptions({
  name: "来票登记",
@@ -113,7 +116,7 @@
    {
      label: "供应商名称",
      prop: "supplierName",
      width:240
      width:200
    },
    {
      label: "项目名称",
@@ -127,12 +130,12 @@
    {
      label: "录入日期",
      prop: "entryDate",
      width:100
      width:110
    },
    {
      label: "合同金额(元)",
      prop: "contractAmount",
      width:150,
      width:200,
      formatData: (val) => {
        return val ? parseFloat(val).toFixed(2) : 0;
      },
@@ -140,7 +143,7 @@
    {
      label: "已开票金额(元)",
      prop: "receiptPaymentAmount",
      width:150,
      width:200,
      formatData: (val) => {
        return val ? parseFloat(val).toFixed(2) : 0;
      },
@@ -148,7 +151,7 @@
    {
      label: "待开票金额(元)",
      prop: "unReceiptPaymentAmount",
      width:150,
      width:200,
      formatData: (val) => {
        return val ? parseFloat(val).toFixed(2) : 0;
      },
@@ -182,8 +185,50 @@
  modalRef.value.open(type, id);
};
const handleOut = () => {};
const handleDelete = () => {};
// å¯¼å‡º
const handleOut = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/purchase/registration/export", {}, "来票登记.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
// åˆ é™¤
const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
    // æ–°å¢žåˆ¤æ–­ï¼šå¦‚果有选中的数据没有ticketRegistrationId,提示并终止
    const noTicket = selectedRows.value.some(item => !item.ticketRegistrationId);
    if (noTicket) {
      proxy.$modal.msgWarning("采购台账还未进行来票登记,无法进行删除操作");
      return;
    }
        ids = selectedRows.value.map((item) => item.ticketRegistrationId);
    } else {
        proxy.$modal.msgWarning("请选择数据");
        return;
    }
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            delRegistration(ids).then((res) => {
                proxy.$modal.msgSuccess("删除成功");
                getList();
            });
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
const expandChange = async (row, expandedRows) => {
  if (expandedRows.length > 0) {
@@ -196,7 +241,17 @@
  pagination.currentPage = page;
  onCurrentChange(page);
};
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
    return proxy.summarizeTable(
        param,
        ["contractAmount", "receiptPaymentAmount", "unReceiptPaymentAmount"],
        {
            ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
            futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
        }
    );
};
onMounted(() => {
  getTableData();
});
src/views/procurementManagement/invoiceEntry/indexOld.vue
@@ -296,19 +296,19 @@
          <el-table-column label="录入日期" prop="createTime" width="120" />
          <el-table-column
            label="含税单价(元)"
            width="150"
            width="200"
            prop="taxInclusiveUnitPrice"
            :formatter="formattedNumber"
          />
          <el-table-column
            label="含税总价(元)"
            width="150"
            width="200"
            prop="taxInclusiveTotalPrice"
            :formatter="formattedNumber"
          />
          <el-table-column
            label="不含税总价(元)"
            width="150"
            width="200"
            prop="taxExclusiveTotalPrice"
            :formatter="formattedNumber"
          />
@@ -331,7 +331,7 @@
            :min="0"
            :step="0.1"
            :formatter="formattedNumber"
            width="170"
            width="200"
          >
            <template #default="scope">
              <el-input-number
src/views/procurementManagement/paymentEntry/index.vue
@@ -72,7 +72,7 @@
        @selection-change="handleSelectionChange"
        :tableLoading="tableLoading"
        @pagination="pagination"
        :total="total"
        :total="page.total"
      ></PIMTable>
    </div>
    <el-dialog
@@ -278,8 +278,8 @@
const page = reactive({
  current: 1,
  size: 100,
    total: 0,
});
const total = ref(0);
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref("");
@@ -348,7 +348,7 @@
  invoiceListPage({ ...searchForm, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.records;
    total.value = res.total;
        page.total = res.total;
  });
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
src/views/procurementManagement/paymentHistory/index.vue
@@ -46,7 +46,7 @@
        @selection-change="handleSelectionChange"
        :tableLoading="tableLoading"
        @pagination="pagination"
        :total="total"
        :total="page.total"
      ></PIMTable>
    </div>
  </div>
@@ -97,6 +97,7 @@
const page = reactive({
  current: 1,
  size: 100,
  total: 0,
});
const total = ref(0);
const { form: searchForm } = useFormData({
@@ -126,7 +127,7 @@
  paymentHistoryListPage({ ...rest, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.records;
    total.value = res.total;
        page.total = res.total;
  });
};
// å­è¡¨åˆè®¡æ–¹æ³•
src/views/procurementManagement/paymentLedger/index.vue
@@ -86,6 +86,7 @@
            :tableLoading="tableLoadingSon"
            :isShowSummary="isShowSummarySon"
            :summaryMethod="summarizeMainTable1"
                        height="calc(100vh - 18.5em)"
          >
            <template #payableAmountSlot="{ row }">
              <el-text type="danger">
@@ -164,10 +165,12 @@
  {
    label: "发生日期",
    prop: "happenTime",
        width: 110,
  },
  {
    label: "发票金额(元)",
    prop: "invoiceAmount",
        width: 200,
    formatData: (params) => {
      return params ? parseFloat(params).toFixed(2) : 0;
    },
@@ -175,6 +178,7 @@
  {
    label: "付款金额(元)",
    prop: "currentPaymentAmount",
        width: 200,
    formatData: (params) => {
      return params ? parseFloat(params).toFixed(2) : 0;
    },
@@ -182,6 +186,7 @@
  {
    label: "应付金额(元)",
    dataType: "slot",
        width: 200,
    prop: "payableAmount",
    slot: "payableAmountSlot",
  },
src/views/procurementManagement/procurementInvoiceLedger/Form/EditForm.vue
@@ -12,8 +12,8 @@
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="含税总价(元):">
          <el-text type="primary">{{ form.taxInclusiveTotalPrice }}</el-text>
        <el-form-item label="含税单价(元):">
          <el-text type="primary">{{ form.taxInclusiveUnitPrice }}</el-text>
        </el-form-item>
      </el-col>
      <el-col :span="12">
@@ -28,12 +28,17 @@
      </el-col>
      <el-col :span="12">
        <el-form-item label="来票数:">
          <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.ticketsNum" @input="inputTicketsNum" />
          <el-input-number :step="0.1" :min="0" style="width: 100%" v-model="form.ticketsNum" @change="inputTicketsNum" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="本次来票金额(元):">
          <el-text type="success">{{ form.ticketsAmount }}</el-text>
                    <el-input-number :step="0.1" :min="0" style="width: 100%" v-model="form.ticketsAmount" @change="inputTicketsAmount" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="未来票数:">
          <el-text type="success">{{ form.futureTickets }}</el-text>
        </el-form-item>
      </el-col>
    </el-row>
@@ -43,6 +48,7 @@
<script setup>
import useFormData from "@/hooks/useFormData";
import { getProductRecordById } from "@/api/procurementManagement/procurementInvoiceLedger";
const { proxy } = getCurrentInstance()
defineOptions({
  name: "来票台账表单",
@@ -56,7 +62,7 @@
  invoiceNumber: undefined, // å‘票号
  ticketsNum: undefined, // æ¥ç¥¨æ•°
  ticketsAmount: undefined, // æ¥ç¥¨é‡‘额
  taxInclusiveTotalPrice: undefined, // å«ç¨Žæ€»ä»·
    taxInclusiveUnitPrice: undefined, // å«ç¨Žå•ä»·
});
const load = async (id) => {
@@ -69,12 +75,46 @@
    form.invoiceNumber = data.invoiceNumber;
    form.ticketsNum = data.ticketsNum;
    form.ticketsAmount = data.ticketsAmount.toFixed(2);
    form.taxInclusiveTotalPrice = data.taxInclusiveTotalPrice;
    form.taxInclusiveUnitPrice = data.taxInclusiveUnitPrice;
    form.futureTickets = data.futureTickets;
  }
};
const inputTicketsNum = (val) => {
  form.ticketsAmount = (val * form.taxInclusiveTotalPrice).toFixed(2);
    // ç¡®ä¿å«ç¨Žå•价存在且不为零
    if (!form.taxInclusiveUnitPrice || Number(form.taxInclusiveUnitPrice) === 0) {
        proxy.$modal.msgWarning("含税单价不能为零或未定义");
        return;
    }
    if (Number(form.ticketsNum) > Number(form.futureTickets)) {
        proxy.$modal.msgWarning("开票数不得大于未开票数");
        form.ticketsNum = form.futureTickets
        return;
    }
    // ç¡®ä¿æ‰€æœ‰æ•°å€¼éƒ½è½¬æ¢ä¸ºæ•°å­—类型进行计算
    const ticketsAmount = Number(val) * Number(form.taxInclusiveUnitPrice);
    form.ticketsAmount = Number(ticketsAmount.toFixed(2));
};
const inputTicketsAmount = (val) => {
    // ç¡®ä¿å«ç¨Žå•价存在且不为零
    if (!form.taxInclusiveUnitPrice || Number(form.taxInclusiveUnitPrice) === 0) {
        proxy.$modal.msgWarning("含税单价不能为零或未定义");
        return;
    }
    if (Number(val) > Number(form.futureTickets*form.taxInclusiveUnitPrice)) {
        proxy.$modal.msgWarning("本次来票金额不得大于总金额");
        form.ticketsAmount = (form.futureTickets*form.taxInclusiveUnitPrice).toFixed(2)
        const ticketsNum = Number(form.ticketsAmount) / Number(form.taxInclusiveUnitPrice);
        form.ticketsNum = Number(ticketsNum.toFixed(2))
        return;
    }
    // ç¡®ä¿æ‰€æœ‰æ•°å€¼éƒ½è½¬æ¢ä¸ºæ•°å­—类型进行计算
    const ticketsNum = Number(val) / Number(form.taxInclusiveUnitPrice);
    form.ticketsNum = Number(ticketsNum.toFixed(2));
};
defineExpose({
src/views/procurementManagement/procurementInvoiceLedger/index.vue
@@ -142,45 +142,37 @@
    {
      label: "采购合同号",
      prop: "purchaseContractNumber",
      align: "center",
      width: 150,
    },
    {
      label: "销售合同号",
      prop: "salesContractNo",
      align: "center",
      width: 150,
    },
    {
      label: "客户名称",
      prop: "customerName",
      align: "center",
      width: 150,
    },
    {
      label: "供应商名称",
      prop: "supplierName",
      align: "center",
      width: 240,
    },
    {
      label: "规格型号",
      prop: "specificationModel",
      align: "center",
      width: 150,
    },
    {
      label: "发票号",
      prop: "invoiceNumber",
      align: "center",
      width: 200,
    },
    {
      label: "合同金额(元)",
      prop: "taxInclusiveTotalPrice",
      align: "center",
      width: 120,
      width: 200,
      formatData: (cell) => {
        return cell ? parseFloat(cell).toFixed(2) : 0;
      },
@@ -188,14 +180,12 @@
    {
      label: "开票日期",
      prop: "createdAt",
      align: "center",
      width: 100,
      width: 110,
    },
    {
      label: "开票金额",
      prop: "ticketsAmount",
      align: "center",
      width: 100,
      width: 200,
      formatData: (cell) => {
        return cell ? parseFloat(cell).toFixed(2) : 0;
      },
@@ -203,8 +193,7 @@
    {
      label: "不含税金额",
      prop: "unTicketsPrice",
      align: "center",
      width: 100,
      width: 200,
      formatData: (cell) => {
        return cell ? parseFloat(cell).toFixed(2) : 0;
      },
@@ -212,14 +201,14 @@
    {
      label: "增值税",
      prop: "invoiceAmount",
      align: "center",
      width: 100,
      width: 200,
    },
    {
      label: "附件",
      align: "center",
      prop: "commonFiles",
      dataType: "slot",
            fixed: "right",
      slot: "commonFilesRef",
      width: 150,
    },
src/views/procurementManagement/procurementLedger/index.vue
@@ -106,7 +106,7 @@
        <el-table-column
          label="合同金额(元)"
          prop="contractAmount"
           width="100"
           width="200"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
@@ -429,18 +429,20 @@
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
              <el-input-number
              :step="0.1"
                clearable
                style="width: 100%"
                v-model="productForm.quantity"
                placeholder="请输入"
                @change="mathNum"
              />
            </el-form-item>
          </el-col>
                    <el-col :span="12">
                        <el-form-item label="税率(%):" prop="taxRate">
                            <el-select
                                v-model="productForm.taxRate"
                                placeholder="请选择"
                                clearable
                                @change="mathNum"
                            >
                                <el-option label="1" value="1" />
                                <el-option label="6" value="6" />
                                <el-option label="13" value="13" />
                            </el-select>
                        </el-form-item>
                    </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
@@ -455,20 +457,18 @@
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="税率(%):" prop="taxRate">
              <el-select
                v-model="productForm.taxRate"
                placeholder="请选择"
                clearable
                @change="mathNum"
              >
                <el-option label="1" value="1" />
                <el-option label="6" value="6" />
                <el-option label="13" value="13" />
              </el-select>
            </el-form-item>
          </el-col>
                    <el-col :span="12">
                        <el-form-item label="数量:" prop="quantity">
                            <el-input-number
                                :step="0.1"
                                clearable
                                style="width: 100%"
                                v-model="productForm.quantity"
                                placeholder="请输入"
                                @change="mathNum"
                            />
                        </el-form-item>
                    </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
@@ -479,7 +479,7 @@
                :step="0.1"
                clearable
                style="width: 100%"
                disabled
                @change="reverseMathNum('taxInclusiveTotalPrice')"
              />
            </el-form-item>
          </el-col>
@@ -488,7 +488,10 @@
              label="不含税总价(元):"
              prop="taxExclusiveTotalPrice"
            >
              <el-input v-model="productForm.taxExclusiveTotalPrice" disabled />
              <el-input
                v-model="productForm.taxExclusiveTotalPrice"
                @change="reverseMathNum('taxExclusiveTotalPrice')"
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -788,6 +791,10 @@
// ç§»é™¤æ–‡ä»¶
function handleRemove(file) {
  console.log("handleRemove", file.id);
  if (file.size > 1024 * 1024 * 10) {
    // ä»…前端清理,不调用删除接口和提示
    return;
  }
  if (operationType.value === "edit") {
    let ids = [];
    ids.push(file.id);
@@ -1010,7 +1017,10 @@
  return `${year}-${month}-${day}`;
}
const mathNum = () => {
  console.log("productForm.value", productForm.value);
    if (!productForm.value.taxRate) {
        proxy.$modal.msgWarning("请先选择税率");
        return;
    }
  if (!productForm.value.taxInclusiveUnitPrice) {
    return;
  }
@@ -1032,6 +1042,43 @@
      );
  }
};
const reverseMathNum = (field) => {
    if (!productForm.value.taxRate) {
        proxy.$modal.msgWarning("请先选择税率");
        return;
    }
  const taxRate = Number(productForm.value.taxRate);
  if (!taxRate) return;
  if (field === 'taxInclusiveTotalPrice') {
    // å·²çŸ¥å«ç¨Žæ€»ä»·å’Œæ•°é‡ï¼Œåç®—含税单价
    if (productForm.value.quantity) {
      productForm.value.taxInclusiveUnitPrice =
        (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2);
    }
    // å·²çŸ¥å«ç¨Žæ€»ä»·å’Œå«ç¨Žå•价,反算数量
    else if (productForm.value.taxInclusiveUnitPrice) {
      productForm.value.quantity =
        (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2);
    }
    // åç®—不含税总价
    productForm.value.taxExclusiveTotalPrice =
      (Number(productForm.value.taxInclusiveTotalPrice) / (1 + taxRate / 100)).toFixed(2);
  } else if (field === 'taxExclusiveTotalPrice') {
    // åç®—含税总价
    productForm.value.taxInclusiveTotalPrice =
      (Number(productForm.value.taxExclusiveTotalPrice) * (1 + taxRate / 100)).toFixed(2);
    // å·²çŸ¥æ•°é‡ï¼Œåç®—含税单价
    if (productForm.value.quantity) {
      productForm.value.taxInclusiveUnitPrice =
        (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2);
    }
    // å·²çŸ¥å«ç¨Žå•价,反算数量
    else if (productForm.value.taxInclusiveUnitPrice) {
      productForm.value.quantity =
        (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2);
    }
  }
};
// é”€å”®åˆåŒé€‰æ‹©æ”¹å˜æ–¹æ³•
const salesLedgerChange = async (row) => {
  console.log("row", row);
src/views/qualityManagement/finalInspection/components/filesDia.vue
@@ -29,9 +29,17 @@
          :tableLoading="tableLoading"
          :isSelection="true"
          @selection-change="handleSelectionChange"
          height="600"
          height="500"
      >
      </PIMTable>
            <pagination
                style="margin: 10px 0"
                v-show="total > 0"
                @pagination="paginationSearch"
                :total="total"
                :page="page.current"
                :limit="page.size"
            />
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="closeDia">取消</el-button>
@@ -57,6 +65,7 @@
  qualityInspectFileDel,
  qualityInspectFileListPage
} from "@/api/qualityManagement/qualityInspectFile.js";
import Pagination from "@/components/PIMTable/Pagination.vue";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
@@ -68,14 +77,6 @@
    label: "文件名称",
    prop: "name",
  },
  // {
  //   label: "上传人",
  //   prop: "createUser",
  // },
  // {
  //   label: "上传时间",
  //   prop: "createTime",
  // },
  {
    dataType: "action",
    label: "操作",
@@ -91,6 +92,11 @@
    ],
  },
]);
const page = reactive({
    current: 1,
    size: 100,
});
const total = ref(0);
const tableData = ref([]);
const fileList = ref([]);
const tableLoading = ref(false);
@@ -105,9 +111,15 @@
  currentId.value = row.id;
  getList()
}
const paginationSearch = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
};
const getList = () => {
  qualityInspectFileListPage({inspectId: currentId.value}).then(res => {
    tableData.value = res.data.records;
        total.value = res.data.total;
  })
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
src/views/qualityManagement/finalInspection/components/formDia.vue
@@ -119,7 +119,7 @@
    unit: [{ required: false, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    checkCompany: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: true, message: "请输入", trigger: "change" }],
  },
});
const { form, rules } = toRefs(data);
src/views/qualityManagement/finalInspection/index.vue
@@ -222,7 +222,7 @@
    type: "warning",
  })
      .then(() => {
        proxy.download("/quality/qualityInspect/export", {inspectType: 2}, "过程检验.xlsx");
        proxy.download("/quality/qualityInspect/export", {inspectType: 2}, "出厂检验.xlsx");
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
src/views/qualityManagement/processInspection/components/filesDia.vue
@@ -29,9 +29,17 @@
          :tableLoading="tableLoading"
          :isSelection="true"
          @selection-change="handleSelectionChange"
          height="600"
          height="500"
      >
      </PIMTable>
            <pagination
                style="margin: 10px 0"
                v-show="total > 0"
                @pagination="paginationSearch"
                :total="total"
                :page="page.current"
                :limit="page.size"
            />
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="closeDia">取消</el-button>
@@ -57,6 +65,7 @@
  qualityInspectFileDel,
  qualityInspectFileListPage
} from "@/api/qualityManagement/qualityInspectFile.js";
import Pagination from "@/components/PIMTable/Pagination.vue";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
@@ -68,14 +77,6 @@
    label: "文件名称",
    prop: "name",
  },
  // {
  //   label: "上传人",
  //   prop: "createUser",
  // },
  // {
  //   label: "上传时间",
  //   prop: "createTime",
  // },
  {
    dataType: "action",
    label: "操作",
@@ -91,6 +92,11 @@
    ],
  },
]);
const page = reactive({
    current: 1,
    size: 100,
});
const total = ref(0);
const tableData = ref([]);
const fileList = ref([]);
const tableLoading = ref(false);
@@ -105,9 +111,15 @@
  currentId.value = row.id;
  getList()
}
const paginationSearch = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
};
const getList = () => {
  qualityInspectFileListPage({inspectId: currentId.value}).then(res => {
    tableData.value = res.data.records;
        total.value = res.data.total;
  })
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
src/views/qualityManagement/processInspection/components/formDia.vue
@@ -126,7 +126,7 @@
    unit: [{ required: false, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    checkCompany: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: true, message: "请输入", trigger: "change" }],
  },
});
const { form, rules } = toRefs(data);
src/views/qualityManagement/rawMaterialInspection/components/filesDia.vue
@@ -29,9 +29,17 @@
          :tableLoading="tableLoading"
          :isSelection="true"
          @selection-change="handleSelectionChange"
          height="600"
          height="500"
      >
      </PIMTable>
            <pagination
                style="margin: 10px 0"
                v-show="total > 0"
                @pagination="paginationSearch"
                :total="total"
                :page="page.current"
                :limit="page.size"
            />
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="closeDia">取消</el-button>
@@ -57,6 +65,7 @@
  qualityInspectFileDel,
  qualityInspectFileListPage
} from "@/api/qualityManagement/qualityInspectFile.js";
import Pagination from "@/components/PIMTable/Pagination.vue";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
@@ -68,14 +77,6 @@
    label: "文件名称",
    prop: "name",
  },
  // {
  //   label: "上传人",
  //   prop: "createUser",
  // },
  // {
  //   label: "上传时间",
  //   prop: "createTime",
  // },
  {
    dataType: "action",
    label: "操作",
@@ -91,6 +92,11 @@
    ],
  },
]);
const page = reactive({
    current: 1,
    size: 100,
});
const total = ref(0);
const tableData = ref([]);
const fileList = ref([]);
const tableLoading = ref(false);
@@ -105,9 +111,15 @@
  currentId.value = row.id;
  getList()
}
const paginationSearch = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
};
const getList = () => {
  qualityInspectFileListPage({inspectId: currentId.value}).then(res => {
  qualityInspectFileListPage({inspectId: currentId.value, ...page}).then(res => {
    tableData.value = res.data.records;
        total.value = res.data.total;
  })
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
@@ -137,7 +137,7 @@
    unit: [{ required: false, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    checkCompany: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: true, message: "请选择检测结果", trigger: "change" }],
  },
});
const { form, rules } = toRefs(data);
src/views/salesManagement/invoiceLedger/index.vue
@@ -38,7 +38,7 @@
        <el-table-column label="规格型号" prop="specificationModel" width="300" show-overflow-tooltip />
        <el-table-column label="发票号" prop="invoiceNo" width="200" show-overflow-tooltip />
        <el-table-column label="发票金额(元)" prop="invoiceTotal" show-overflow-tooltip :formatter="formattedNumber"
          width="120" />
          width="200" />
        <el-table-column label="税率(%)" prop="taxRate" show-overflow-tooltip />
        <el-table-column label="录入人" prop="invoicePerson" show-overflow-tooltip />
        <el-table-column label="录入日期" prop="createTime" show-overflow-tooltip :formatter="formatDate" width="180" />
src/views/salesManagement/invoiceRegistration/index.vue
@@ -151,7 +151,7 @@
          prop="contractAmount"
          show-overflow-tooltip
          :formatter="formattedNumber"
          width="120"
                    width="220"
        />
        <el-table-column
@@ -297,16 +297,18 @@
          />
          <el-table-column label="单位" prop="unit" />
          <el-table-column label="数量" prop="quantity" width="70" />
          <el-table-column label="税率(%)" prop="taxRate" width="70" />
          <el-table-column label="税率(%)" prop="taxRate" width="80" />
          <el-table-column
            label="含税单价(元)"
            prop="taxInclusiveUnitPrice"
            :formatter="formattedNumber"
                        width="200"
          />
          <el-table-column
            label="含税总价(元)"
            prop="taxInclusiveTotalPrice"
            :formatter="formattedNumber"
                        width="200"
          />
          <el-table-column
            label="不含税总价(元)"
@@ -314,27 +316,27 @@
            :formatter="formattedNumber"
            width="150"
          />
          <el-table-column label="本次开票数" prop="currentInvoiceNum" width="150">
          <el-table-column label="本次开票数" prop="currentInvoiceNum" width="180">
            <template #default="scope">
              <el-input-number :step="0.1" :min="0" style="width: 100%"
                v-model="scope.row.currentInvoiceNum"
                @blur="invoiceNumBlur(scope.row)"
                @change="invoiceNumBlur(scope.row)"
              ></el-input-number>
            </template>
          </el-table-column>
          <el-table-column
            label="本次开票金额(元)"
            prop="currentInvoiceAmount"
            width="150"
            width="180"
          >
            <template #default="scope">
              <el-input-number :step="0.01" :min="0" style="width: 100%"
                v-model="scope.row.currentInvoiceAmount"
                @blur="invoiceAmountBlur(scope.row)"
                @change="invoiceAmountBlur(scope.row)"
              ></el-input-number>
            </template>
          </el-table-column>
          <el-table-column label="未开票数" prop="noInvoiceNum" width="100">
          <el-table-column label="未开票数" prop="noInvoiceNum" width="120">
            <template #default="scope">
              <el-input
                type="number"
@@ -347,7 +349,7 @@
          <el-table-column
            label="未开票金额(元)"
            prop="noInvoiceAmount"
            width="150"
            width="200"
          >
            <template #default="scope">
              <el-input
@@ -537,6 +539,7 @@
    "currentInvoiceAmount",
    "noInvoiceNum",
    "noInvoiceAmount",
    "currentInvoiceNum",
  ]);
};
// æ‰“开弹框
src/views/salesManagement/receiptPayment/index.vue
@@ -184,7 +184,7 @@
          prop="invoiceTotal"
          show-overflow-tooltip
          :formatter="formattedNumber"
          width="150"
          width="200"
        />
        <el-table-column label="税率(%)" prop="taxRate" show-overflow-tooltip />
        <el-table-column
@@ -192,13 +192,13 @@
          prop="receiptPaymentAmountTotal"
          show-overflow-tooltip
          :formatter="formattedNumber"
          width="150"
          width="200"
        />
        <el-table-column
          label="待回款金额(元)"
          prop="noReceiptAmount"
          show-overflow-tooltip
          width="150"
          width="200"
        >
          <template #default="{ row, column }">
            <el-text type="danger">
src/views/salesManagement/receiptPaymentHistory/index.vue
@@ -101,7 +101,7 @@
  {
    label: "回款金额(元)",
    prop: "receiptPaymentAmount",
    width:150,
    width:200,
    formatData: (params) => {
      return params ? parseFloat(params).toFixed(2) : 0;
    },
src/views/salesManagement/receiptPaymentLedger/index.vue
@@ -38,23 +38,27 @@
            label="客户名称"
            prop="customerName"
            show-overflow-tooltip
                        width="200"
          />
          <el-table-column
            label="开票金额(元)"
            prop="invoiceTotal"
            show-overflow-tooltip
            :formatter="formattedNumber"
                        width="200"
          />
          <el-table-column
            label="回款金额(元)"
            prop="receiptPaymentAmount"
            show-overflow-tooltip
            :formatter="formattedNumber"
                        width="200"
          />
          <el-table-column
            label="应收金额(元)"
            prop="unReceiptPaymentAmount"
            show-overflow-tooltip
                        width="200"
          >
            <template #default="{ row, column }">
              <el-text type="danger">
@@ -91,23 +95,27 @@
            label="发生日期"
            prop="happenTime"
            show-overflow-tooltip
                        width="110"
          />
          <el-table-column
            label="开票金额(元)"
            prop="invoiceAmount"
            show-overflow-tooltip
            :formatter="formattedNumber"
                        width="200"
          />
          <el-table-column
            label="回款金额(元)"
            prop="receiptAmount"
            show-overflow-tooltip
            :formatter="formattedNumber"
                        width="200"
          />
          <el-table-column
            label="应收金额(元)"
            prop="unReceiptAmount"
            show-overflow-tooltip
                        width="200"
          >
            <template #default="{ row, column }">
              <el-text type="danger">
src/views/salesManagement/salesLedger/index.vue
@@ -64,7 +64,7 @@
        <el-table-column label="业务员" prop="salesman" width="100" show-overflow-tooltip />
        <el-table-column label="项目名称" prop="projectName" width="180" show-overflow-tooltip />
        <el-table-column label="付款方式" prop="paymentMethod" show-overflow-tooltip />
        <el-table-column label="合同金额(元)" prop="contractAmount" width="180" show-overflow-tooltip
        <el-table-column label="合同金额(元)" prop="contractAmount" width="220" show-overflow-tooltip
          :formatter="formattedNumber" />
        <el-table-column label="录入人" prop="entryPersonName" width="100" show-overflow-tooltip />
        <el-table-column label="录入日期" prop="entryDate" width="120" show-overflow-tooltip />
@@ -235,38 +235,39 @@
              <el-input v-model="productForm.unit" placeholder="请输入" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
              <el-input-number  :step="0.1" :min="0" v-model="productForm.quantity" placeholder="请输入" clearable
                @change="mathNum" style="width: 100%" />
            </el-form-item>
          </el-col>
                    <el-col :span="12">
                        <el-form-item label="税率(%):" prop="taxRate">
                            <el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="calculateFromTaxRate">
                                <el-option label="1" value="1" />
                                <el-option label="6" value="6" />
                                <el-option label="13" value="13" />
                            </el-select>
                        </el-form-item>
                    </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice">
              <el-input-number :step="0.01" :min="0" v-model="productForm.taxInclusiveUnitPrice" style="width: 100%" placeholder="请输入" clearable @change="mathNum" />
              <el-input-number :step="0.01" :min="0" v-model="productForm.taxInclusiveUnitPrice" style="width: 100%"
                                                             placeholder="请输入" clearable @change="calculateFromUnitPrice" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="税率(%):" prop="taxRate">
              <el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="mathNum">
                <el-option label="1" value="1" />
                <el-option label="6" value="6" />
                <el-option label="13" value="13" />
              </el-select>
            </el-form-item>
          </el-col>
                    <el-col :span="12">
                        <el-form-item label="数量:" prop="quantity">
                            <el-input-number  :step="0.1" :min="0" v-model="productForm.quantity" placeholder="请输入" clearable
                                                                @change="calculateFromQuantity" style="width: 100%" />
                        </el-form-item>
                    </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice">
              <el-input v-model="productForm.taxInclusiveTotalPrice" placeholder="请输入" clearable disabled />
              <el-input v-model="productForm.taxInclusiveTotalPrice" placeholder="请输入" clearable @change="calculateFromTotalPrice" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice">
              <el-input v-model="productForm.taxExclusiveTotalPrice" placeholder="请输入" clearable disabled />
              <el-input v-model="productForm.taxExclusiveTotalPrice" placeholder="请输入" clearable @change="calculateFromExclusiveTotalPrice" />
            </el-form-item>
          </el-col>
        </el-row>
@@ -413,6 +414,8 @@
  },
});
const { productForm, productRules } = toRefs(productFormData);
// é˜²æ­¢å¾ªçŽ¯è®¡ç®—çš„æ ‡å¿—
const isCalculating = ref(false);
const upload = reactive({
  // ä¸Šä¼ çš„地址
  url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
@@ -808,6 +811,154 @@
      );
  }
};
// æ ¹æ®å«ç¨Žæ€»ä»·è®¡ç®—含税单价和数量
const calculateFromTotalPrice = () => {
  if (isCalculating.value) return;
  const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
  const quantity = parseFloat(productForm.value.quantity);
  if (!totalPrice || !quantity || quantity <= 0) {
    return;
  }
  isCalculating.value = true;
  // è®¡ç®—含税单价 = å«ç¨Žæ€»ä»· / æ•°é‡
  productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
  // å¦‚果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
        totalPrice,
        productForm.value.taxRate
      );
  }
  isCalculating.value = false;
};
// æ ¹æ®ä¸å«ç¨Žæ€»ä»·è®¡ç®—含税单价和数量
const calculateFromExclusiveTotalPrice = () => {
    if (!productForm.value.taxRate) {
        proxy.$modal.msgWarning("请先选择税率");
        return;
    }
  if (isCalculating.value) return;
  const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice);
  const quantity = parseFloat(productForm.value.quantity);
  const taxRate = parseFloat(productForm.value.taxRate);
  if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
    return;
  }
  isCalculating.value = true;
  // å…ˆè®¡ç®—含税总价 = ä¸å«ç¨Žæ€»ä»· / (1 - ç¨Žçއ/100)
  const taxRateDecimal = taxRate / 100;
  const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
  productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
  // è®¡ç®—含税单价 = å«ç¨Žæ€»ä»· / æ•°é‡
  productForm.value.taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2);
  isCalculating.value = false;
};
// æ ¹æ®æ•°é‡å˜åŒ–计算总价
const calculateFromQuantity = () => {
    if (!productForm.value.taxRate) {
        proxy.$modal.msgWarning("请先选择税率");
        return;
    }
  if (isCalculating.value) return;
  const quantity = parseFloat(productForm.value.quantity);
  const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
  if (!quantity || quantity <= 0 || !unitPrice) {
    return;
  }
  isCalculating.value = true;
  // è®¡ç®—含税总价
  productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
  // å¦‚果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
      );
  }
  isCalculating.value = false;
};
// æ ¹æ®å«ç¨Žå•价变化计算总价
const calculateFromUnitPrice = () => {
    if (!productForm.value.taxRate) {
        proxy.$modal.msgWarning("请先选择税率");
        return;
    }
  if (isCalculating.value) return;
  const quantity = parseFloat(productForm.value.quantity);
  const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
  if (!quantity || quantity <= 0 || !unitPrice) {
    return;
  }
  isCalculating.value = true;
  // è®¡ç®—含税总价
  productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
  // å¦‚果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
      );
  }
  isCalculating.value = false;
};
// æ ¹æ®ç¨ŽçŽ‡å˜åŒ–è®¡ç®—ä¸å«ç¨Žæ€»ä»·
const calculateFromTaxRate = () => {
    if (!productForm.value.taxRate) {
        proxy.$modal.msgWarning("请先选择税率");
        return;
    }
  if (isCalculating.value) return;
  const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
  const taxRate = parseFloat(productForm.value.taxRate);
  if (!inclusiveTotalPrice || !taxRate) {
    return;
  }
  isCalculating.value = true;
  // è®¡ç®—不含税总价
  productForm.value.taxExclusiveTotalPrice =
    proxy.calculateTaxExclusiveTotalPrice(
      inclusiveTotalPrice,
      taxRate
    );
  isCalculating.value = false;
};
/**
 * ä¸‹è½½æ–‡ä»¶
 *