| | |
| | | }); |
| | | } |
| | | |
| | | // 清除当前用户的全部消息 |
| | | export function clearAllMessage() { |
| | | return request({ |
| | | url: "/system/notice/clearAll", |
| | | method: "delete", |
| | | }); |
| | | } |
| | | |
| | | // 确认消息 |
| | | export function confirmMessage(noticeId, status) { |
| | | return request({ |
| | |
| | | {{ formatters(scope.row[item.prop], item.formatData) }} |
| | | </el-tag> |
| | | </div> |
| | | <!-- 时间类型 --> |
| | | <div v-else-if="item.dataType === 'date'"> |
| | | {{ scope.row[item.prop] ? dayjs(scope.row[item.prop]).format('YYYY-MM-DD') : '' }} |
| | | </div> |
| | | <!-- 按钮 --> |
| | | <div v-else-if="item.dataType == 'action'" |
| | | @click.stop> |
| | |
| | | import pagination from "./Pagination.vue"; |
| | | import { computed, ref, inject, getCurrentInstance } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | // 获取全局的 uploadHeader |
| | | const { proxy } = getCurrentInstance(); |
| | |
| | | <div class="notification-popover-content"> |
| | | <div class="popover-header"> |
| | | <span class="popover-title">消息通知</span> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="handleMarkAllAsRead" |
| | | :disabled="unreadCount === 0"> |
| | | 一键已读 |
| | | </el-button> |
| | | <div class="popover-actions"> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="handleMarkAllAsRead" |
| | | :disabled="unreadCount === 0"> |
| | | 一键已读 |
| | | </el-button> |
| | | <el-button type="danger" |
| | | size="small" |
| | | plain |
| | | @click="handleClearAll"> |
| | | 清除 |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <div class="notification-content"> |
| | | <el-tabs v-model="activeTab" |
| | |
| | | listMessage, |
| | | markAsRead, |
| | | markAllAsRead, |
| | | clearAllMessage, |
| | | confirmMessage, |
| | | getUnreadCount, |
| | | } from "@/api/system/message"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { useRouter } from "vue-router"; |
| | | |
| | |
| | | } |
| | | }; |
| | | |
| | | // 清除全部消息 |
| | | const handleClearAll = async () => { |
| | | try { |
| | | await ElMessageBox.confirm("确认清除全部消息吗?清除后无法恢复。", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }); |
| | | } catch (error) { |
| | | // 取消清除 |
| | | return; |
| | | } |
| | | try { |
| | | const res = await clearAllMessage(); |
| | | if (res.code === 200) { |
| | | ElMessage.success("清除成功"); |
| | | unreadList.value = []; |
| | | readList.value = []; |
| | | total.value = 0; |
| | | pageNum.value = 1; |
| | | loadMessages(); |
| | | loadUnreadCount(); |
| | | } |
| | | } catch (error) { |
| | | console.error("清除消息失败:", error); |
| | | ElMessage.error("清除失败"); |
| | | } |
| | | }; |
| | | |
| | | // 分页大小改变 |
| | | const handleSizeChange = size => { |
| | | pageSize.value = size; |
| | |
| | | font-weight: 500; |
| | | color: var(--text-primary); |
| | | } |
| | | |
| | | .popover-actions { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | } |
| | | |
| | | .notification-content { |
| | |
| | | */
|
| | |
|
| | | // 日期格式化
|
| | | export function parseDate(time, pattern) {
|
| | | if (arguments.length === 0 || !time) {
|
| | | return null
|
| | | }
|
| | | const format = pattern || '{y}-{m}-{d}'
|
| | | let date
|
| | | if (typeof time === 'object') {
|
| | | date = time
|
| | | } else {
|
| | | if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
|
| | | time = parseInt(time)
|
| | | } else if (typeof time === 'string') {
|
| | | time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '')
|
| | | }
|
| | | if ((typeof time === 'number') && (time.toString().length === 10)) {
|
| | | time = time * 1000
|
| | | }
|
| | | date = new Date(time)
|
| | | }
|
| | | const formatObj = {
|
| | | y: date.getFullYear(),
|
| | | m: date.getMonth() + 1,
|
| | | d: date.getDate(),
|
| | | h: date.getHours(),
|
| | | i: date.getMinutes(),
|
| | | s: date.getSeconds(),
|
| | | a: date.getDay()
|
| | | }
|
| | | const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
| | | let value = formatObj[key]
|
| | | // Note: getDay() returns 0 on Sunday
|
| | | if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
|
| | | if (result.length > 0 && value < 10) {
|
| | | value = '0' + value
|
| | | }
|
| | | return value || 0
|
| | | })
|
| | | return time_str
|
| | | }
|
| | |
|
| | | // 日期格式化
|
| | | export function parseTime(time, pattern) {
|
| | | if (arguments.length === 0 || !time) {
|
| | | return null
|
| | |
| | | }); |
| | | return sums; |
| | | }; |
| | | // 不含税总价计算 |
| | | const calculateTaxExclusiveTotalPrice = (taxInclusiveTotalPrice, taxRate) => { |
| | | // 不含税总价计算,decimals 为保留小数位数(销售/采购相关页面传 6) |
| | | const calculateTaxExclusiveTotalPrice = ( |
| | | taxInclusiveTotalPrice, |
| | | taxRate, |
| | | decimals = 2 |
| | | ) => { |
| | | const taxRateDecimal = taxRate / 100; |
| | | return (taxInclusiveTotalPrice / (1 + taxRateDecimal)).toFixed(2); |
| | | return (taxInclusiveTotalPrice / (1 + taxRateDecimal)).toFixed(decimals); |
| | | }; |
| | | // 含税总价计算 |
| | | const calculateTaxIncludeTotalPrice = (taxInclusiveUnitPrice, quantity) => { |
| | | return (taxInclusiveUnitPrice * quantity).toFixed(2); |
| | | // 含税总价计算,decimals 为保留小数位数(销售/采购相关页面传 6) |
| | | const calculateTaxIncludeTotalPrice = ( |
| | | taxInclusiveUnitPrice, |
| | | quantity, |
| | | decimals = 2 |
| | | ) => { |
| | | return (taxInclusiveUnitPrice * quantity).toFixed(decimals); |
| | | }; |
| | | // 导出函数供其他文件使用 |
| | | export { |
| | |
| | | { |
| | | label: "创建时间", |
| | | prop: "createTime", |
| | | dataType:"date" |
| | | }, |
| | | { |
| | | label: "操作", |
| | |
| | | const formCreateTimeDate = computed({ |
| | | get: () => (formData.createTime ? String(formData.createTime).split(" ")[0] : ""), |
| | | set: (value) => { |
| | | formData.createTime = value ? `${value} ${dayjs().format("HH:mm:ss")}` : ""; |
| | | formData.createTime = value ? dayjs(value).format("YYYY-MM-DD") : ""; |
| | | }, |
| | | }); |
| | | // const productTypes = ref([]); |
| | |
| | | name: "产品维护导入", |
| | | }); |
| | | |
| | | const props = defineProps({ |
| | | productId: { type: [String, Number], default: "" }, |
| | | }); |
| | | const emits = defineEmits(["uploadSuccess"]); |
| | | const fileUploadRef = ref(); |
| | | const upload = reactive({ |
| | | // 是否显示弹出层(供应商导入) |
| | | open: false, |
| | | // 弹出层标题(供应商导入) |
| | | title: "", |
| | | title: "产品导入", |
| | | // 是否禁用上传 |
| | | isUploading: false, |
| | | // 设置上传的请求头部 |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | }); |
| | | // 上传的地址(携带 productId 参数,传给后端的 importProduct 接口) |
| | | const uploadUrl = computed( |
| | | () => |
| | | import.meta.env.VITE_APP_BASE_API + |
| | | "/basic/product/import" + |
| | | (props.productId ? `?productId=${props.productId}` : "") |
| | | ); |
| | | // 上传的地址 |
| | | const uploadUrl = computed(() => import.meta.env.VITE_APP_BASE_API + "/basic/product/import"); |
| | | // 点击导入 |
| | | const handleImport = () => { |
| | | if (!props.productId) { |
| | | ElMessage({ message: "请先选择产品", type: "warning" }); |
| | | return; |
| | | } |
| | | upload.open = true; |
| | | upload.title = "产品导入"; |
| | | }; |
| | | |
| | | const submitFileForm = () => { |
| | |
| | | @clear="searchFilter" |
| | | clearable |
| | | prefix-icon="Search" /> |
| | | <span style="margin-left: 12px"> |
| | | <ImportExcel @uploadSuccess="handleImportSuccess" /> |
| | | </span> |
| | | <el-button v-if="false" |
| | | type="primary" |
| | | @click="openProDia('addOne')" |
| | |
| | | @click="openModelDia('add')"> |
| | | 新增规格型号 |
| | | </el-button> |
| | | <ImportExcel :product-id="currentId" |
| | | @uploadSuccess="getModelList" /> |
| | | <el-button type="danger" |
| | | @click="handleDelete" |
| | | style="margin-left: 10px" |
| | |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | // 导入完成后刷新产品树与右侧规格列表 |
| | | const handleImportSuccess = () => { |
| | | getProductTreeList(); |
| | | if (currentId.value) { |
| | | getModelList(); |
| | | } |
| | | }; |
| | | // 删除规格型号 |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="使用次数" prop="usageCount"> |
| | | <el-input-number v-model="form.usageCount" :min="0" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- <el-col :span="12">--> |
| | | <!-- <el-form-item label="使用次数" prop="usageCount">--> |
| | | <!-- <el-input-number v-model="form.usageCount" :min="0" style="width: 100%" />--> |
| | | <!-- </el-form-item>--> |
| | | <!-- </el-col>--> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | |
| | | {{ getEfficiencyLabel(currentKnowledge.efficiency) }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="使用次数"> |
| | | <el-tag type="info">{{ currentKnowledge.usageCount }} 次</el-tag> |
| | | </el-descriptions-item> |
| | | <!-- <el-descriptions-item label="使用次数">--> |
| | | <!-- <el-tag type="info">{{ currentKnowledge.usageCount }} 次</el-tag>--> |
| | | <!-- </el-descriptions-item>--> |
| | | <el-descriptions-item label="创建人"> |
| | | {{ currentKnowledge.creator }} |
| | | </el-descriptions-item> |
| | |
| | | <h4>使用统计</h4> |
| | | <div class="usage-stats"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="8"> |
| | | <div class="stat-item"> |
| | | <div class="stat-number">{{ currentKnowledge.usageCount }}</div> |
| | | <div class="stat-label">使用次数</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <!-- <el-col :span="8">--> |
| | | <!-- <div class="stat-item">--> |
| | | <!-- <div class="stat-number">{{ currentKnowledge.usageCount }}</div>--> |
| | | <!-- <div class="stat-label">使用次数</div>--> |
| | | <!-- </div>--> |
| | | <!-- </el-col>--> |
| | | <el-col :span="12"> |
| | | <div class="stat-item"> |
| | | <div class="stat-number">{{ getEfficiencyScore(currentKnowledge.efficiency) }}%</div> |
| | | <div class="stat-label">效率提升</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-col :span="12"> |
| | | <div class="stat-item"> |
| | | <div class="stat-number">{{ getTimeSaved(currentKnowledge.efficiency) }}</div> |
| | | <div class="stat-label">平均节省时间</div> |
| | |
| | | return typeMap[params] || "info"; |
| | | } |
| | | }, |
| | | { |
| | | label: "文件数量", |
| | | prop: "fileCount", |
| | | width: 100, |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "切片数量", |
| | | prop: "totalChunkCount", |
| | | width: 100, |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "使用次数", |
| | | prop: "usageCount", |
| | | width: 100, |
| | | align: "center" |
| | | }, |
| | | // { |
| | | // label: "文件数量", |
| | | // prop: "fileCount", |
| | | // width: 100, |
| | | // align: "center" |
| | | // }, |
| | | // { |
| | | // label: "切片数量", |
| | | // prop: "totalChunkCount", |
| | | // width: 100, |
| | | // align: "center" |
| | | // }, |
| | | // { |
| | | // label: "使用次数", |
| | | // prop: "usageCount", |
| | | // width: 100, |
| | | // align: "center" |
| | | // }, |
| | | { |
| | | label: "创建人", |
| | | prop: "creator", |
| | |
| | | label: "创建时间", |
| | | prop: "createTime", |
| | | width: 180, |
| | | dataType:"date" |
| | | }, |
| | | { |
| | | dataType: "action", |
| | |
| | | openFilesDialog(row); |
| | | } |
| | | }, |
| | | { |
| | | name: "问答", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openChatDialog(row); |
| | | } |
| | | }, |
| | | // { |
| | | // name: "问答", |
| | | // type: "text", |
| | | // clickFun: (row) => { |
| | | // openChatDialog(row); |
| | | // } |
| | | // }, |
| | | { |
| | | name: "详情", |
| | | type: "text", |
| | |
| | | }, |
| | | { label: "版本", prop: "version", width: 120 }, |
| | | { label: "发布人", prop: "createUserName", width: 120 }, |
| | | { label: "发布时间", prop: "createTime", width: 180 }, |
| | | { label: "发布时间", prop: "createTime", width: 180,dataType: "date" }, |
| | | { |
| | | label: "状态", |
| | | prop: "status", |
| | |
| | | formatData: (v) => getSealTypeText(v), |
| | | formatType: () => 'info' |
| | | }, |
| | | { label: '申请时间', prop: 'createTime', width: 180 }, |
| | | { label: '申请时间', prop: 'createTime', width: 180,dataType: "date" }, |
| | | { |
| | | label: '状态', |
| | | prop: 'status', |
| | |
| | | <el-descriptions-item label="含税总价">{{ detailData.taxIncludingPriceTotal }}</el-descriptions-item> |
| | | <el-descriptions-item label="税率(%)">{{ detailData.taxRate }}</el-descriptions-item> |
| | | <el-descriptions-item label="不含税总价">{{ detailData.unTaxIncludingPriceTotal }}</el-descriptions-item> |
| | | <el-descriptions-item label="录入日期">{{ detailData.createTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="录入日期">{{ detailData.createTime ? dayjs(detailData.createTime).format('YYYY-MM-DD') : '' }}</el-descriptions-item> |
| | | <el-descriptions-item label="预计运行时间">{{ detailData.planRuntimeTime ? dayjs(detailData.planRuntimeTime).format('YYYY-MM-DD') : '' }}</el-descriptions-item> |
| | | <el-descriptions-item label="设备图片" :span="2"> |
| | | <div v-if="detailData.storageBlobVOs && detailData.storageBlobVOs.length > 0" style="display: flex; gap: 10px; flex-wrap: wrap;"> |
| | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="验收时间"> |
| | | <el-input v-model="form.acceptanceTime" |
| | | disabled /> |
| | | <el-date-picker |
| | | v-model="form.acceptanceTime" |
| | | type="date" |
| | | value-format="yyyy-MM-dd" |
| | | placeholder="选择验收时间" |
| | | :disabled="true" |
| | | ></el-date-picker> |
| | | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | |
| | | form.storageBlobDTOs = data.storageBlobVOs || []; |
| | | form.maintenanceName = data.maintenanceName; |
| | | form.acceptanceName = data.acceptanceName; |
| | | form.acceptanceTime = data.acceptanceTime; |
| | | form.acceptanceTime = data.acceptanceTime |
| | | ? dayjs(data.acceptanceTime).format("YYYY-MM-DD") |
| | | : undefined; |
| | | form.acceptanceRemark = data.acceptanceRemark; |
| | | }; |
| | | |
| | |
| | | { label: "备件名称", prop: "sparePartsName" }, |
| | | { label: "领用数量", prop: "quantity" }, |
| | | { label: "操作人", prop: "operator" }, |
| | | { label: "时间", prop: "createTime" }, |
| | | { label: "时间", prop: "createTime",dataType:"date" }, |
| | | ]); |
| | | |
| | | const handleTabChange = async (name) => { |
| | |
| | | label: "登记日期", |
| | | minWidth: 100, |
| | | formatData: cell => |
| | | cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : "-", |
| | | cell ? dayjs(cell).format("YYYY-MM-DD") : "-", |
| | | }, |
| | | { |
| | | fixed: "right", |
| | |
| | | { label: "退货单号", prop: "returnNo", minWidth: "150" }, |
| | | { label: "供应商", prop: "supplierName", minWidth: "180" }, |
| | | { label: "关联入库单号", prop: "inboundBatches", minWidth: "150" }, |
| | | { label: "退货日期", prop: "preparedAt", minWidth: "170" }, |
| | | { label: "退货日期", prop: "preparedAt", minWidth: "170",dataType: "date"}, |
| | | { |
| | | label: "退款总额", |
| | | prop: "totalAmount", |
| | |
| | | { label: "退货单号", prop: "returnNo", minWidth: "150" }, |
| | | { label: "客户名称", prop: "customerName", minWidth: "180" }, |
| | | { label: "关联发货单号", prop: "shippingNo", minWidth: "150" }, |
| | | { label: "退货日期", prop: "makeTime", minWidth: "170" }, |
| | | { label: "退货日期", prop: "makeTime", minWidth: "170",dataType: "date" }, |
| | | { |
| | | label: "退款总额", |
| | | prop: "refundAmount", |
| | |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="出库日期" |
| | | prop="createTime" |
| | | show-overflow-tooltip /> |
| | | show-overflow-tooltip > |
| | | <template #default="scope"> |
| | | {{ scope.row.createTime ? scope.row.createTime.split(' ')[0] : '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="产品大类" |
| | | prop="productName" |
| | | show-overflow-tooltip /> |
| | |
| | | prop="inboundBatches" |
| | | width="200" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="入库时间" |
| | | prop="createTime" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="入库时间" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ scope.row.createTime ? scope.row.createTime.split(' ')[0] : '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="产品大类" |
| | | prop="productName" |
| | | show-overflow-tooltip /> |
| | |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="备注" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column |
| | | label="最近更新时间" |
| | | prop="updateTime" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="最近更新时间" |
| | | prop="updateTime" |
| | | show-overflow-tooltip > |
| | | <template #default="scope"> |
| | | {{ scope.row.updateTime ? scope.row.updateTime.split(' ')[0] : '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="操作" min-width="180" align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | |
| | | <el-table-column label="冻结数量" prop="lockedQuantity" show-overflow-tooltip /> |
| | | <el-table-column label="库存预警数量" prop="warnNum" show-overflow-tooltip /> |
| | | <el-table-column label="备注" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column label="最近更新时间" prop="updateTime" show-overflow-tooltip /> |
| | | <el-table-column label="最近更新时间" |
| | | prop="updateTime" |
| | | show-overflow-tooltip > |
| | | <template #default="scope"> |
| | | {{ scope.row.updateTime ? scope.row.updateTime.split(' ')[0] : '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="操作" min-width="90" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" @click="showSubtractModal(scope.row)" :disabled="scope.row.unLockedQuantity === 0">领用</el-button> |
| | |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="最近更新时间" |
| | | prop="updateTime" |
| | | show-overflow-tooltip /> |
| | | show-overflow-tooltip > |
| | | <template #default="scope"> |
| | | {{ scope.row.updateTime ? scope.row.updateTime.split(' ')[0] : '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" |
| | | label="操作" |
| | | min-width="80" |
| | |
| | | <el-table-column label="库存数量" prop="qualitity" show-overflow-tooltip /> |
| | | <el-table-column label="冻结数量" prop="lockedQuantity" show-overflow-tooltip /> |
| | | <el-table-column label="备注" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column label="最近更新时间" prop="updateTime" show-overflow-tooltip /> |
| | | <el-table-column label="最近更新时间" |
| | | prop="updateTime" |
| | | show-overflow-tooltip > |
| | | <template #default="scope"> |
| | | {{ scope.row.updateTime ? scope.row.updateTime.split(' ')[0] : '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="操作" min-width="90" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" @click="showSubtractModal(scope.row)" :disabled="scope.row.unLockedQuantity === 0">领用</el-button> |
| | |
| | | prop="createTime" |
| | | width="200" |
| | | show-overflow-tooltip |
| | | v-if="searchForm.reportType !== 'inout'" /> |
| | | v-if="searchForm.reportType !== 'inout'" > |
| | | <template #default="scope"> |
| | | {{ getDate(scope.row.createTime) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="入库批次" |
| | | prop="inboundBatches" |
| | | width="180" |
| | |
| | | import { ref, reactive, onMounted, nextTick, getCurrentInstance } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import * as echarts from "echarts"; |
| | | import dayjs from "dayjs"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | getStockInventoryInAndOutReportList, |
| | |
| | | ); |
| | | }; |
| | | |
| | | const getDate = val =>{ |
| | | console.log(val) |
| | | if(!val){ |
| | | return "--" |
| | | } |
| | | return dayjs(val).isValid() ? dayjs(val).format('YYYY‑MM‑DD') : '--' |
| | | } |
| | | |
| | | // 获取来源类型选项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | findAllQualifiedStockInRecordTypeOptions().then(res => { |
| | |
| | | <el-table-column label="描述" align="center" prop="msg" :show-overflow-tooltip="true" />
|
| | | <el-table-column label="访问时间" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
|
| | | <template #default="scope">
|
| | | <span>{{ parseTime(scope.row.loginTime) }}</span>
|
| | | <span>{{ parseDate(scope.row.loginTime) }}</span>
|
| | | </template>
|
| | | </el-table-column>
|
| | | </el-table>
|
| | |
| | |
|
| | | <script setup name="Logininfor">
|
| | | import { list, delLogininfor, cleanLogininfor, unlockLogininfor } from "@/api/monitor/logininfor"
|
| | | import {parseDate} from "@/utils/ruoyi.js";
|
| | |
|
| | | const { proxy } = getCurrentInstance()
|
| | | const { sys_common_status } = proxy.useDict("sys_common_status")
|
| | |
| | | </el-table-column>
|
| | | <el-table-column label="操作日期" align="center" prop="operTime" width="180" sortable="custom" :sort-orders="['descending', 'ascending']">
|
| | | <template #default="scope">
|
| | | <span>{{ parseTime(scope.row.operTime) }}</span>
|
| | | <span>{{ dayjs(scope.row.operTime).format("YYYY-MM-DD") }}</span>
|
| | | </template>
|
| | | </el-table-column>
|
| | | <el-table-column label="消耗时间" align="center" prop="costTime" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']">
|
| | |
| | | <el-col :span="24">
|
| | | <el-form-item label="操作方法:">{{ form.method }}</el-form-item>
|
| | | </el-col>
|
| | | <el-col :span="24">
|
| | | <el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>
|
| | | </el-col>
|
| | | <!-- <el-col :span="24">-->
|
| | | <!-- <el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>-->
|
| | | <!-- </el-col>-->
|
| | | <el-col :span="24">
|
| | | <el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
|
| | | </el-col>
|
| | |
| | | <el-form-item label="消耗时间:">{{ form.costTime }}毫秒</el-form-item>
|
| | | </el-col>
|
| | | <el-col :span="8">
|
| | | <el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
|
| | | <el-form-item label="操作时间:">{{ dayjs(form.operTime).format("YYYY-MM-DD") }}</el-form-item>
|
| | | </el-col>
|
| | | <el-col :span="24">
|
| | | <el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
|
| | |
| | | <script setup name="Operlog">
|
| | | import { list, delOperlog, cleanOperlog } from "@/api/monitor/operlog"
|
| | | import {onMounted} from "vue";
|
| | | import dayjs from "dayjs";
|
| | |
|
| | | const { proxy } = getCurrentInstance()
|
| | | const { sys_oper_type, sys_common_status } = proxy.useDict("sys_oper_type","sys_common_status")
|
| | |
| | | if (val == null || val === "") return ""; |
| | | if (Array.isArray(val) && val.length >= 3) { |
| | | const [y, m, d, h = 0, min = 0, s = 0] = val; |
| | | return dayjs(new Date(y, m - 1, d, h, min, s)).format("YYYY-MM-DD HH:mm:ss"); |
| | | // return dayjs(new Date(y, m - 1, d, h, min, s)).format("YYYY-MM-DD HH:mm:ss"); |
| | | return dayjs(new Date(y, m - 1, d, h, min, s)).format("YYYY-MM-DD"); |
| | | |
| | | } |
| | | if (typeof val === "number") { |
| | | const d = val > 1e12 ? dayjs(val) : dayjs.unix(val); |
| | | return d.isValid() ? d.format("YYYY-MM-DD HH:mm:ss") : ""; |
| | | return d.isValid() ? d.format("YYYY-MM-DD") : ""; |
| | | } |
| | | const s = String(val).trim(); |
| | | if (!s) return ""; |
| | | const parsed = dayjs(s.includes("T") ? s : s.replace(/-/g, "/")); |
| | | return parsed.isValid() ? parsed.format("YYYY-MM-DD HH:mm:ss") : s; |
| | | return parsed.isValid() ? parsed.format("YYYY-MM-DD") : s; |
| | | } |
| | | |
| | | export function formatDisplayTime(val) { |
| | |
| | | <!-- 第一行:合同开始 / 合同结束 / 试用期 / 转正 --> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="入职日期" prop="contractStartTime"> |
| | | <el-form-item label="合同开始日期" prop="contractStartTime"> |
| | | <el-date-picker |
| | | v-model="form.contractStartTime" |
| | | type="date" |
| | |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "入职日期", |
| | | label: "合同开始日期", |
| | | prop: "contractStartTime", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "转正日期", |
| | | prop: "positiveDate", |
| | | width: 120, |
| | | dataType: "slot", |
| | | slot: "positiveDate", |
| | | }, |
| | | // { |
| | | // label: "转正日期", |
| | | // prop: "positiveDate", |
| | | // width: 120, |
| | | // dataType: "slot", |
| | | // slot: "positiveDate", |
| | | // }, |
| | | { |
| | | label: "年龄", |
| | | prop: "age", |
| | |
| | | { label: "保险类型", prop: "insuranceTypes", width: 120 }, |
| | | { label: "使用范围", prop: "deptNames", width: 120 }, |
| | | { label: "备注", prop: "remark", minWidth: 120 }, |
| | | { label: "创建时间", prop: "createTime", width: 160 }, |
| | | { label: "创建时间", prop: "createTime", width: 160,dataType: "date" }, |
| | | { label: "创建人", prop: "createUserName", width: 100 }, |
| | | { |
| | | dataType: "action", |
| | |
| | | @pagination="sonPaginationSearch"> |
| | | <template #payableAmountSlot="{ row }"> |
| | | <el-text type="danger"> |
| | | {{ parseFloat(row.payableAmount).toFixed(2) }} |
| | | {{ parseFloat(row.payableAmount).toFixed(6) }} |
| | | </el-text> |
| | | </template> |
| | | <template #paymentActionSlot="{ row }"> |
| | |
| | | <el-date-picker style="width:100%" v-model="paymentForm.paymentDate" value-format="YYYY-MM-DD" type="date" placeholder="请选择付款日期" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="付款金额:" prop="paymentAmount"> |
| | | <el-input-number style="width:100%" v-model="paymentForm.paymentAmount" :precision="2" :min="0" :max="Math.max(0,(Number(currentPaymentRow.payableAmount)||0)-(Number(currentPaymentRow.paymentAmount)||0))" placeholder="请输入付款金额" controls-position="right" /> |
| | | <div style="color:#e6a23c;font-size:12px;margin-top:4px">当前可付款余额:{{ Math.max(0,(Number(currentPaymentRow.payableAmount)||0)-(Number(currentPaymentRow.paymentAmount)||0)).toFixed(2) }} 元</div> |
| | | <el-input-number style="width:100%" v-model="paymentForm.paymentAmount" :min="0" :precision="6" :max="Math.max(0,(Number(currentPaymentRow.payableAmount)||0)-(Number(currentPaymentRow.paymentAmount)||0))" placeholder="请输入付款金额" controls-position="right" /> |
| | | <div style="color:#e6a23c;font-size:12px;margin-top:4px">当前可付款余额:{{ Math.max(0,(Number(currentPaymentRow.payableAmount)||0)-(Number(currentPaymentRow.paymentAmount)||0)).toFixed(6) }} 元</div> |
| | | </el-form-item> |
| | | <el-form-item label="付款方式:" prop="paymentMethod"> |
| | | <el-select v-model="paymentForm.paymentMethod" placeholder="请选择付款方式" style="width:100%" clearable> |
| | |
| | | prop: "contractAmount", |
| | | width: 200, |
| | | formatData: params => { |
| | | return params ? parseFloat(params).toFixed(2) : 0; |
| | | return params ? parseFloat(params).toFixed(6) : 0; |
| | | }, |
| | | }, |
| | | { |
| | |
| | | prop: "paymentAmount", |
| | | width: 200, |
| | | formatData: params => { |
| | | return params ? parseFloat(params).toFixed(2) : 0; |
| | | return params ? parseFloat(params).toFixed(6) : 0; |
| | | }, |
| | | }, |
| | | { |
| | |
| | | const currentPaymentRow = ref({}); |
| | | const paymentFormRef = ref(null); |
| | | const paymentForm = reactive({ paymentDate:"", paymentAmount:undefined, paymentMethod:"", remark:"" }); |
| | | const validatePaymentAmount = (_,v,cb) => { |
| | | if(!v) return cb(new Error("请输入付款金额")); |
| | | const max = Math.max(0,(Number(currentPaymentRow.value.payableAmount)||0)-(Number(currentPaymentRow.value.paymentAmount)||0)); |
| | | if(v > max) return cb(new Error(`付款金额不能超过可付款余额 ${max.toFixed(2)} 元`)); |
| | | cb(); |
| | | }; |
| | | const paymentRules = { |
| | | paymentDate:[{required:true,message:"请选择付款日期",trigger:"change"}], |
| | | paymentAmount:[{required:true,validator:validatePaymentAmount,trigger:"blur"}], |
| | | paymentMethod:[{required:true,message:"请选择付款方式",trigger:"change"}], |
| | | }; |
| | | const openPaymentDialog = row => { currentPaymentRow.value=row; paymentForm.paymentDate=""; paymentForm.paymentAmount=undefined; paymentForm.paymentMethod=""; paymentForm.remark=""; paymentDialogVisible.value=true; }; |
| | | const validatePaymentAmount = (_,v,cb) => { if(!v) return cb(new Error("请输入付款金额")); const m=Math.max(0,(Number(currentPaymentRow.value.payableAmount)||0)-(Number(currentPaymentRow.value.paymentAmount)||0)); if(v>m) return cb(new Error(`付款金额不能超过可付款余额 ${m.toFixed(6)} 元`)); cb(); }; |
| | | const paymentRules = { paymentDate:[{required:true,message:"请选择付款日期",trigger:"change"}], paymentAmount:[{required:true,validator:validatePaymentAmount,trigger:"blur"}], paymentMethod:[{required:true,message:"请选择付款方式",trigger:"change"}] }; |
| | | const openPaymentDialog = r => { currentPaymentRow.value=r; paymentForm.paymentDate=""; paymentForm.paymentAmount=undefined; paymentForm.paymentMethod=""; paymentForm.remark=""; paymentDialogVisible.value=true; }; |
| | | const closePaymentDialog = () => { paymentFormRef.value?.resetFields(); paymentDialogVisible.value=false; }; |
| | | const submitPaymentForm = () => { |
| | | paymentFormRef.value?.validate(valid => { |
| | | if(valid){ |
| | | savePayment({ supplierId:currentSupplierId.value, purchaseContractNumber:currentPaymentRow.value.purchaseContractNumber, paymentDate:paymentForm.paymentDate, paymentAmount:paymentForm.paymentAmount, paymentMethod:paymentForm.paymentMethod, remark:paymentForm.remark }).then(res => { |
| | | proxy.$modal.msgSuccess("新增付款成功"); closePaymentDialog(); getPaymenRecordtList(currentSupplierId.value); getList(); |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | const submitPaymentForm = () => { paymentFormRef.value?.validate(v=>{ if(v){ savePayment({ supplierId:currentSupplierId.value, purchaseContractNumber:currentPaymentRow.value.purchaseContractNumber, paymentDate:paymentForm.paymentDate, paymentAmount:paymentForm.paymentAmount, paymentMethod:paymentForm.paymentMethod, remark:paymentForm.remark }).then(res=>{ proxy.$modal.msgSuccess("新增付款成功"); closePaymentDialog(); getPaymenRecordtList(currentSupplierId.value); getList(); }); } }); }; |
| | | |
| | | // 主表合计方法 |
| | | const summarizeMainTable = param => { |
| | |
| | | param, |
| | | ["contractAmounts", "paymentAmount", "payableAmount"], |
| | | { |
| | | contractAmounts: { decimalPlaces: 6 }, |
| | | paymentAmount: { decimalPlaces: 6 }, |
| | | payableAmount: { decimalPlaces: 6 }, |
| | | ticketsNum: { noDecimal: true }, // 不保留小数 |
| | | futureTickets: { noDecimal: true }, // 不保留小数 |
| | | } |
| | |
| | | param, |
| | | ["contractAmount", "invoiceAmount", "paymentAmount"], |
| | | { |
| | | contractAmount: { decimalPlaces: 6 }, |
| | | invoiceAmount: { decimalPlaces: 6 }, |
| | | paymentAmount: { decimalPlaces: 6 }, |
| | | ticketsNum: { noDecimal: true }, // 不保留小数 |
| | | futureTickets: { noDecimal: true }, // 不保留小数 |
| | | } |
| | |
| | | summarizeTable[summarizeTable.length - 1] = |
| | | originalTableDataSon.value[ |
| | | originalTableDataSon.value.length - 1 |
| | | ].payableAmount.toFixed(2); |
| | | ].payableAmount.toFixed(6); |
| | | } else { |
| | | summarizeTable[summarizeTable.length - 1] = 0.0; |
| | | } |
| | |
| | | }; |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | if (column.property !== "supplierName") { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | return parseFloat(cellValue).toFixed(6); |
| | | } else { |
| | | return cellValue; |
| | | } |
| | |
| | | <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;"> |
| | | <el-button type="success" |
| | | plain |
| | | v-if="false" |
| | | @click="handleBatchGenerate">批量生成数据</el-button> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">新增台账</el-button> |
| | |
| | | prop="purchaseContractNumber" |
| | | width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="销售合同号" |
| | | prop="salesContractNo" |
| | | width="160" |
| | | show-overflow-tooltip /> |
| | | <!-- <el-table-column label="销售合同号"--> |
| | | <!-- prop="salesContractNo"--> |
| | | <!-- width="160"--> |
| | | <!-- show-overflow-tooltip />--> |
| | | <el-table-column label="供应商名称" |
| | | prop="supplierName" |
| | | width="160" |
| | |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="合同金额(元)" |
| | | prop="contractAmount" |
| | | width="200" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="实际合同金额(元)" |
| | | prop="netContractAmount" |
| | | width="200" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | |
| | | <el-form-item label="含税单价(元):" |
| | | prop="taxInclusiveUnitPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveUnitPrice" |
| | | :precision="2" |
| | | :precision="6" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | |
| | | prop="quantity"> |
| | | <el-input-number :step="0.1" |
| | | clearable |
| | | :precision="2" |
| | | :precision="6" |
| | | :min="0" |
| | | style="width: 100%" |
| | | v-model="productForm.quantity" |
| | |
| | | <el-form-item label="含税总价(元):" |
| | | prop="taxInclusiveTotalPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveTotalPrice" |
| | | :precision="2" |
| | | :precision="6" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | |
| | | <el-form-item label="不含税总价(元):" |
| | | prop="taxExclusiveTotalPrice"> |
| | | <el-input-number v-model="productForm.taxExclusiveTotalPrice" |
| | | :precision="2" |
| | | :precision="6" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | |
| | | <el-form-item label="库存预警数量:" |
| | | prop="warnNum"> |
| | | <el-input-number v-model="productForm.warnNum" |
| | | :precision="2" |
| | | :precision="6" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | |
| | | }; |
| | | |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | return parseFloat(cellValue).toFixed(6); |
| | | }; |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | |
| | | "futureTicketsAmount", |
| | | ], |
| | | { |
| | | taxInclusiveUnitPrice: { decimalPlaces: 6 }, |
| | | taxInclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | taxExclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | ticketsAmount: { decimalPlaces: 6 }, |
| | | futureTicketsAmount: { decimalPlaces: 6 }, |
| | | ticketsNum: { noDecimal: true }, // 不保留小数 |
| | | futureTickets: { noDecimal: true }, // 不保留小数 |
| | | } |
| | |
| | | }; |
| | | // 主表合计方法 |
| | | const summarizeMainTable = param => { |
| | | return proxy.summarizeTable(param, ["contractAmount"]); |
| | | return proxy.summarizeTable( |
| | | param, |
| | | ["contractAmount", "netContractAmount"], |
| | | { |
| | | contractAmount: { decimalPlaces: 6 }, |
| | | netContractAmount: { decimalPlaces: 6 }, |
| | | } |
| | | ); |
| | | }; |
| | | // 子表合计方法 |
| | | const summarizeProTable = param => { |
| | | return proxy.summarizeTable(param, [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | ]); |
| | | return proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | ], |
| | | { |
| | | taxInclusiveUnitPrice: { decimalPlaces: 6 }, |
| | | taxInclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | taxExclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | } |
| | | ); |
| | | }; |
| | | // 打开弹框 |
| | | const openForm = async (type, row) => { |
| | |
| | | productForm.value.taxInclusiveTotalPrice = |
| | | proxy.calculateTaxIncludeTotalPrice( |
| | | productForm.value.taxInclusiveUnitPrice, |
| | | productForm.value.quantity |
| | | productForm.value.quantity, |
| | | 6 |
| | | ); |
| | | if (productForm.value.taxRate) { |
| | | // 不含税总价计算 |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | productForm.value.taxInclusiveTotalPrice, |
| | | productForm.value.taxRate |
| | | productForm.value.taxRate, |
| | | 6 |
| | | ); |
| | | } |
| | | }; |
| | |
| | | productForm.value.taxInclusiveUnitPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.quantity) |
| | | ).toFixed(2); |
| | | ).toFixed(6); |
| | | // 确保结果不为负数 |
| | | if (Number(productForm.value.taxInclusiveUnitPrice) < 0) { |
| | | productForm.value.taxInclusiveUnitPrice = "0"; |
| | |
| | | productForm.value.quantity = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.taxInclusiveUnitPrice) |
| | | ).toFixed(2); |
| | | ).toFixed(6); |
| | | // 确保结果不为负数 |
| | | if (Number(productForm.value.quantity) < 0) { |
| | | productForm.value.quantity = "0"; |
| | |
| | | productForm.value.taxExclusiveTotalPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | (1 + taxRate / 100) |
| | | ).toFixed(2); |
| | | ).toFixed(6); |
| | | // 确保结果不为负数 |
| | | if (Number(productForm.value.taxExclusiveTotalPrice) < 0) { |
| | | productForm.value.taxExclusiveTotalPrice = "0"; |
| | |
| | | productForm.value.taxInclusiveTotalPrice = ( |
| | | Number(productForm.value.taxExclusiveTotalPrice) * |
| | | (1 + taxRate / 100) |
| | | ).toFixed(2); |
| | | ).toFixed(6); |
| | | // 确保结果不为负数 |
| | | if (Number(productForm.value.taxInclusiveTotalPrice) < 0) { |
| | | productForm.value.taxInclusiveTotalPrice = "0"; |
| | |
| | | productForm.value.taxInclusiveUnitPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.quantity) |
| | | ).toFixed(2); |
| | | ).toFixed(6); |
| | | // 确保结果不为负数 |
| | | if (Number(productForm.value.taxInclusiveUnitPrice) < 0) { |
| | | productForm.value.taxInclusiveUnitPrice = "0"; |
| | |
| | | productForm.value.quantity = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.taxInclusiveUnitPrice) |
| | | ).toFixed(2); |
| | | ).toFixed(6); |
| | | // 确保结果不为负数 |
| | | if (Number(productForm.value.quantity) < 0) { |
| | | productForm.value.quantity = "0"; |
| | |
| | | <div class="summary-stats"> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">采购总额:</span> |
| | | <span class="stat-value">¥{{ businessSummaryStats.totalAmount.toLocaleString() }}</span> |
| | | <span class="stat-value">¥{{ formatStatAmount(businessSummaryStats.totalAmount) }}</span> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">商品种类:</span> |
| | |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">退款总额:</span> |
| | | <span class="stat-value">{{ businessSummaryStats.returnAmount }}</span> |
| | | <span class="stat-value">¥{{ formatStatAmount(businessSummaryStats.returnAmount) }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | // 统计数据 |
| | | const businessSummaryStats = ref({ |
| | | totalAmount: 0, |
| | | returnAmount: 0, |
| | | productTypes: 0 |
| | | }) |
| | | |
| | | // 汇总金额展示,保留6位小数 |
| | | const formatStatAmount = (val) => { |
| | | return Number(val || 0).toLocaleString('zh-CN', { |
| | | minimumFractionDigits: 6, |
| | | maximumFractionDigits: 6 |
| | | }) |
| | | } |
| | | |
| | | // 表格列配置(根据后端字段定义) |
| | | const tableColumns = ref([ |
| | |
| | | prop: 'purchaseNum', |
| | | width: 120, |
| | | formatData: (val) => { |
| | | return val ? parseFloat(val).toLocaleString() : '0' |
| | | return val ? parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 6, maximumFractionDigits: 6 }) : '0' |
| | | } |
| | | }, |
| | | { |
| | |
| | | prop: 'returnQuantity', |
| | | width: 120, |
| | | formatData: (val) => { |
| | | return val ? parseFloat(val).toLocaleString() : '0' |
| | | return val ? parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 6, maximumFractionDigits: 6 }) : '0' |
| | | } |
| | | }, |
| | | { |
| | |
| | | prop: 'returnAmount', |
| | | width: 120, |
| | | formatData: (val) => { |
| | | return val ? `¥${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : '¥0.00' |
| | | return val ? `¥${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 6, maximumFractionDigits: 6 })}` : '¥0.000000' |
| | | } |
| | | }, |
| | | { |
| | | label: '退款储量', |
| | | prop: 'purchaseAmount', |
| | | formatData: (val) => { |
| | | return val ? `¥${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : '¥0.00' |
| | | return val ? `¥${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 6, maximumFractionDigits: 6 })}` : '¥0.000000' |
| | | } |
| | | }, |
| | | { |
| | |
| | | prop: 'averagePrice', |
| | | width: 120, |
| | | formatData: (val) => { |
| | | return val ? `¥${parseFloat(val).toFixed(2)}` : '¥0.00' |
| | | return val ? `¥${parseFloat(val).toFixed(6)}` : '¥0.000000' |
| | | } |
| | | }, |
| | | { |
| | |
| | | } else { |
| | | businessSummaryStats.value = { |
| | | totalAmount: 0, |
| | | returnAmount: 0, |
| | | productTypes: 0 |
| | | } |
| | | } |
| | |
| | | <el-input-number v-model="scope.row.returnQuantity" |
| | | controls-position="right" |
| | | :step="1" |
| | | :precision="6" |
| | | :min="0" |
| | | :max="getReturnQtyMax(scope.row)" |
| | | :disabled="getReturnQtyMax(scope.row) <= 0" |
| | |
| | | <el-input-number v-model="formState.totalDiscountAmount" |
| | | controls-position="right" |
| | | :step="0.01" |
| | | :precision="2" |
| | | :precision="6" |
| | | style="width: 100%;" |
| | | @change="handleChangeTotalDiscountAmount" |
| | | placeholder="请输入整单折扣额"/> |
| | |
| | | <el-input v-model="formState.totalDiscountRate" |
| | | controls-position="right" |
| | | :step="0.01" |
| | | :precision="2" |
| | | :precision="6" |
| | | style="width: 100%;" |
| | | @change="totalDiscount" |
| | | placeholder="请输入整单折扣率"> |
| | |
| | | <el-input-number v-model="formState.totalAmount" |
| | | controls-position="right" |
| | | :step="0.01" |
| | | :precision="2" |
| | | :precision="6" |
| | | style="width: 100%;" |
| | | placeholder="请输入成交金额"/> |
| | | </el-form-item> |
| | |
| | | }); |
| | | |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | return parseFloat(cellValue).toFixed(6); |
| | | }; |
| | | |
| | | const formatAmount = (value) => { |
| | |
| | | if (Number.isNaN(num)) { |
| | | return '--' |
| | | } |
| | | return num.toFixed(2) |
| | | return num.toFixed(6) |
| | | } |
| | | |
| | | const toNumber = (val) => { |
| | |
| | | const total = Number(row?.stockInNum ?? row?.totalQuantity ?? row?.quantity ?? 0) |
| | | const un = Number(row?.unQuantity ?? 0) |
| | | if (!Number.isFinite(total) || !Number.isFinite(un)) return 0 |
| | | return Math.max(total - un, 0) |
| | | // 保留6位小数,避免浮点减法产生精度误差 |
| | | return Math.max(parseFloat((total - un).toFixed(6)), 0) |
| | | } |
| | | |
| | | const getReturnTotal = (row) => { |
| | | const qty = toNumber(row?.returnQuantity) |
| | | const unitPrice = toNumber(row?.taxInclusiveUnitPrice) |
| | | const total = qty * unitPrice |
| | | return Number(total.toFixed(2)) |
| | | return Number(total.toFixed(6)) |
| | | } |
| | | |
| | | const syncReturnTotal = (row) => { |
| | |
| | | } |
| | | const baseAmount = getBaseAmount() |
| | | // 折扣额 = 产品退货总价合计 * 折扣率 |
| | | formState.value.totalDiscountAmount = Number((baseAmount * (discountRate / 100)).toFixed(2)) |
| | | formState.value.totalDiscountAmount = Number((baseAmount * (discountRate / 100)).toFixed(6)) |
| | | syncTotalAmount() |
| | | } |
| | | |
| | |
| | | "taxExclusiveTotalPrice", |
| | | ], |
| | | { |
| | | stockInNum: { noDecimal: true }, // 不保留小数 |
| | | returnQuantity: { noDecimal: true }, // 不保留小数 |
| | | unQuantity: { noDecimal: true }, // 不保留小数 |
| | | stockInNum: { decimalPlaces: 6 }, |
| | | returnQuantity: { decimalPlaces: 6 }, |
| | | unQuantity: { decimalPlaces: 6 }, |
| | | taxInclusiveUnitPrice: { decimalPlaces: 6 }, |
| | | taxInclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | taxExclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | } |
| | | ); |
| | | }; |
| | |
| | | |
| | | if (normalizedAmount > baseAmount) { |
| | | proxy.$modal.msgError("整单折扣额不能大于产品退货总价合计") |
| | | formState.value.totalDiscountAmount = Number(baseAmount.toFixed(2)) |
| | | formState.value.totalDiscountAmount = Number(baseAmount.toFixed(6)) |
| | | } |
| | | |
| | | const discountRate = (toNumber(formState.value.totalDiscountAmount) / baseAmount) * 100 |
| | | formState.value.totalDiscountRate = Number(discountRate.toFixed(2)) |
| | | formState.value.totalDiscountRate = Number(discountRate.toFixed(6)) |
| | | syncTotalAmount() |
| | | } |
| | | |
| | |
| | | const baseAmount = getBaseAmount() |
| | | const discount = toNumber(formState.value.totalDiscountAmount) |
| | | // 成交金额 = 产品退货总价合计 - 折扣额 |
| | | formState.value.totalAmount = Number((baseAmount - discount).toFixed(2)) |
| | | formState.value.totalAmount = Number((baseAmount - discount).toFixed(6)) |
| | | } |
| | | |
| | | // 获取供应商选项 |
| | |
| | | const selectedRows = ref([]) |
| | | const tableLoading = ref(false) |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | return parseFloat(cellValue).toFixed(6); |
| | | }; |
| | | |
| | | /** 已退货数量 = 入库行总数量 − 当前可退货数量(剩余) */ |
| | |
| | | if (Number.isNaN(num)) { |
| | | return value; |
| | | } |
| | | return num.toFixed(2); |
| | | return num.toFixed(6); |
| | | }; |
| | | |
| | | /** 已退货数量 = 入库行总数量 − 当前可退货数量(剩余) */ |
| | |
| | | const total = Number(row?.stockInNum ?? row?.totalQuantity ?? row?.quantity ?? 0); |
| | | const un = Number(row?.unQuantity ?? 0); |
| | | if (!Number.isFinite(total) || !Number.isFinite(un)) return 0; |
| | | return Math.max(total - un, 0); |
| | | // 保留6位小数,避免浮点减法产生精度误差 |
| | | return Math.max(parseFloat((total - un).toFixed(6)), 0); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | label: "创建时间", |
| | | prop: "createTime", |
| | | width: 120, |
| | | dataType: "date" |
| | | }, |
| | | { |
| | | dataType: "action", |
| | |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="客户名称">{{ rowData.productionOrderDto?.customerName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="开始日期">{{ parseTime(rowData.productionOrderDto?.startTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="开始日期">{{ parseDate(rowData.productionOrderDto?.startTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="完成进度"> |
| | | <el-progress :percentage="rowData.productionOrderDto?.completionStatus>=100?100:rowData.productionOrderDto?.completionStatus" |
| | | :color="customColors(rowData.productionOrderDto?.completionStatus)" |
| | |
| | | <el-descriptions-item label="生产工单号">{{ detailData.workOrder.workOrderNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="计划数量">{{ detailData.workOrder.planQuantity || 0 }}</el-descriptions-item> |
| | | <el-descriptions-item label="完成数量">{{ detailData.workOrder.completeQuantity || 0 }}</el-descriptions-item> |
| | | <el-descriptions-item label="实际开始时间">{{ parseTime(detailData.workOrder.actualStartTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="实际结束时间">{{ parseTime(detailData.workOrder.actualEndTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="实际开始时间">{{ parseDate(detailData.workOrder.actualStartTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="实际结束时间">{{ parseDate(detailData.workOrder.actualEndTime) || '-' }}</el-descriptions-item> |
| | | <!-- <el-descriptions-item label="完成进度"> |
| | | <el-progress :percentage="detailData.workOrder.completionStatus >= 100 ? 100 : (detailData.workOrder.completionStatus || 0)" |
| | | :color="customColors(detailData.workOrder.completionStatus)" |
| | |
| | | <el-table-column label="创建时间" |
| | | align="center"> |
| | | <template #default="{ row }"> |
| | | {{ parseTime(row.createTime) }} |
| | | {{ parseDate(row.createTime) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="工时(h)" |
| | |
| | | :key="record.id" |
| | | class="quality-record-block"> |
| | | <div class="detail-section"> |
| | | <h3 class="section-title">检测记录 {{ index + 1 }} - {{ parseTime(record.createTime) }}</h3> |
| | | <h3 class="section-title">检测记录 {{ index + 1 }} - {{ parseDate(record.checkTime) }}</h3> |
| | | <el-descriptions :column="3" |
| | | border> |
| | | <el-descriptions-item label="检测日期">{{ parseTime(record.createTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="检测日期">{{ parseDate(record.checkTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="报工单号">{{ record.reportNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="检验员">{{ record.userName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产品名称">{{ record.productName || '-' }}</el-descriptions-item> |
| | |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { useRoute, useRouter } from "vue-router"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { parseTime } from "@/utils/ruoyi"; |
| | | import { parseDate } from "@/utils/ruoyi"; |
| | | import InputModal from "@/views/productionManagement/productionReporting/Input.vue"; |
| | | import { |
| | | getOrderDetail, |
| | |
| | | detailData.value = { |
| | | workOrder: row.workOrder || {}, |
| | | reports: (row.reportList || []).map(r => ({ |
| | | ...r.reportMain, |
| | | // 产出数据先展开,报工单数据后展开,保证创建时间用报工单的 |
| | | ...(r.reportOutputList[0] || {}), |
| | | ...r.reportMain, |
| | | productionOperationParamList: r.reportParamList || [], |
| | | })), |
| | | }; |
| | |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | // 数量运算保留6位小数,避免浮点减法出现 7.199999999999999 这类精度误差 |
| | | const toQuantity = val => { |
| | | const n = Number(val); |
| | | if (!Number.isFinite(n)) return 0; |
| | | return parseFloat(n.toFixed(6)); |
| | | }; |
| | | const toProgressPercentage = val => { |
| | | const n = Number(val); |
| | | if (!Number.isFinite(n)) return 0; |
| | |
| | | currentReportRowData.value = row; |
| | | const planQuantity = Number(row.planQuantity || 0); |
| | | const completeQuantity = Number(row.completeQuantity || 0); |
| | | const remainingQuantity = Math.max(0, planQuantity - completeQuantity); |
| | | const remainingQuantity = Math.max( |
| | | 0, |
| | | toQuantity(planQuantity - completeQuantity) |
| | | ); |
| | | reportForm.planQuantity = remainingQuantity; |
| | | reportForm.quantity = |
| | | row.quantity !== undefined && row.quantity !== null ? row.quantity : null; |
| | |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="上报时间" |
| | | prop="createTime" |
| | | show-overflow-tooltip /> |
| | | show-overflow-tooltip > |
| | | <template #default="scope"> |
| | | {{ scope.row.createTime ? scope.row.createTime.split(' ')[0] : '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="整改完成期限" |
| | | prop="rectifyTime" |
| | | width="120" |
| | |
| | | |
| | | <el-dialog v-model="receiptDialogVisible" title="新增回款" width="35%" @close="closeReceiptDialog"> |
| | | <el-form :model="receiptForm" label-width="100px" :rules="receiptRules" ref="receiptFormRef"> |
| | | <el-form-item label="销售合同号:"> {{ currentRow.salesContractNo || '--' }} </el-form-item> |
| | | <el-form-item label="销售合同号:">{{ currentRow.salesContractNo || '--' }}</el-form-item> |
| | | <el-form-item label="回款日期:" prop="paymentDate"> |
| | | <el-date-picker style="width:100%" v-model="receiptForm.paymentDate" value-format="YYYY-MM-DD" type="date" placeholder="请选择回款日期" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="回款金额:" prop="paymentAmount"> |
| | | <el-input-number style="width:100%" v-model="receiptForm.paymentAmount" :precision="2" :min="0" :max="Math.max(0,(Number(currentRow.receiptableAmount)||0)-(Number(currentRow.receiptPaymentAmount)||0))" placeholder="请输入回款金额" controls-position="right" /> |
| | | <el-input-number style="width:100%" v-model="receiptForm.paymentAmount" :min="0" :precision="6" :max="Math.max(0,(Number(currentRow.receiptableAmount)||0)-(Number(currentRow.receiptPaymentAmount)||0))" placeholder="请输入回款金额" controls-position="right" /> |
| | | <div style="color:#e6a23c;font-size:12px;margin-top:4px">当前可回款余额:{{ formattedNumber(null,null,Math.max(0,(Number(currentRow.receiptableAmount)||0)-(Number(currentRow.receiptPaymentAmount)||0))) }} 元</div> |
| | | </el-form-item> |
| | | <el-form-item label="回款方式:" prop="paymentMethod"> |
| | |
| | | const currentRow = ref({}); |
| | | const receiptFormRef = ref(null); |
| | | const receiptForm = reactive({ paymentDate:"", paymentAmount:undefined, paymentMethod:"", remark:"" }); |
| | | const validatePaymentAmount = (_,v,cb) => { |
| | | if(!v) return cb(new Error("请输入回款金额")); |
| | | const max = Math.max(0,(Number(currentRow.value.receiptableAmount)||0)-(Number(currentRow.value.receiptPaymentAmount)||0)); |
| | | if(v > max) return cb(new Error(`回款金额不能超过可回款余额 ${max.toFixed(2)} 元`)); |
| | | cb(); |
| | | }; |
| | | const receiptRules = { |
| | | paymentDate:[{required:true,message:"请选择回款日期",trigger:"change"}], |
| | | paymentAmount:[{required:true,validator:validatePaymentAmount,trigger:"blur"}], |
| | | paymentMethod:[{required:true,message:"请选择回款方式",trigger:"change"}], |
| | | }; |
| | | const openReceiptDialog = row => { currentRow.value=row; receiptForm.paymentDate=""; receiptForm.paymentAmount=undefined; receiptForm.paymentMethod=""; receiptForm.remark=""; receiptDialogVisible.value=true; }; |
| | | const validatePaymentAmount = (_,v,cb) => { if(!v) return cb(new Error("请输入回款金额")); const m=Math.max(0,(Number(currentRow.value.receiptableAmount)||0)-(Number(currentRow.value.receiptPaymentAmount)||0)); if(v>m) return cb(new Error(`回款金额不能超过可回款余额 ${m.toFixed(6)} 元`)); cb(); }; |
| | | const receiptRules = { paymentDate:[{required:true,message:"请选择回款日期",trigger:"change"}], paymentAmount:[{required:true,validator:validatePaymentAmount,trigger:"blur"}], paymentMethod:[{required:true,message:"请选择回款方式",trigger:"change"}] }; |
| | | const openReceiptDialog = r => { currentRow.value=r; receiptForm.paymentDate=""; receiptForm.paymentAmount=undefined; receiptForm.paymentMethod=""; receiptForm.remark=""; receiptDialogVisible.value=true; }; |
| | | const closeReceiptDialog = () => { receiptFormRef.value?.resetFields(); receiptDialogVisible.value=false; }; |
| | | const submitReceiptForm = () => { |
| | | receiptFormRef.value?.validate(valid => { |
| | | if(valid){ |
| | | saveReceiptPayment({ customerId:customerId.value, salesContractNo:currentRow.value.salesContractNo, paymentDate:receiptForm.paymentDate, paymentAmount:receiptForm.paymentAmount, paymentMethod:receiptForm.paymentMethod, remark:receiptForm.remark }).then(res => { |
| | | proxy.$modal.msgSuccess("新增回款成功"); closeReceiptDialog(); receiptPaymentList(customerId.value); getList(); |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | const submitReceiptForm = () => { receiptFormRef.value?.validate(v=>{ if(v){ saveReceiptPayment({ customerId:customerId.value, salesContractNo:currentRow.value.salesContractNo, paymentDate:receiptForm.paymentDate, paymentAmount:receiptForm.paymentAmount, paymentMethod:receiptForm.paymentMethod, remark:receiptForm.remark }).then(res=>{ proxy.$modal.msgSuccess("新增回款成功"); closeReceiptDialog(); receiptPaymentList(customerId.value); getList(); }); } }); }; |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | | const handleQuery = () => { |
| | |
| | | }); |
| | | }; |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return cellValue ? parseFloat(cellValue).toFixed(2) : "0.00"; |
| | | return cellValue ? parseFloat(cellValue).toFixed(6) : "0.000000"; |
| | | }; |
| | | // 主表合计方法 |
| | | const summarizeMainTable = param => { |
| | |
| | | param, |
| | | ["invoiceTotal", "receiptPaymentAmount", "unReceiptPaymentAmount"], |
| | | { |
| | | invoiceTotal: { decimalPlaces: 6 }, |
| | | receiptPaymentAmount: { decimalPlaces: 6 }, |
| | | unReceiptPaymentAmount: { decimalPlaces: 6 }, |
| | | ticketsNum: { noDecimal: true }, // 不保留小数 |
| | | futureTickets: { noDecimal: true }, // 不保留小数 |
| | | } |
| | |
| | | param, |
| | | ["contractAmount", "receiptPaymentAmount", "receiptableAmount"], |
| | | { |
| | | contractAmount: { decimalPlaces: 6 }, |
| | | receiptPaymentAmount: { decimalPlaces: 6 }, |
| | | receiptableAmount: { decimalPlaces: 6 }, |
| | | ticketsNum: { noDecimal: true }, // 不保留小数 |
| | | futureTickets: { noDecimal: true }, // 不保留小数 |
| | | } |
| | |
| | | raw?.canReturnQuantity, |
| | | returnQuantity: Number.isFinite(num) ? num : 0, |
| | | price: Number(raw?.taxInclusiveUnitPrice ?? raw?.price ?? 0), |
| | | amount: Number(raw?.amount ?? 0).toFixed(2), |
| | | amount: Number(raw?.amount ?? 0).toFixed(6), |
| | | isQuality: raw?.isQuality ?? 2, |
| | | remark: raw?.remark ?? "", |
| | | }; |
| | |
| | | const total = Number(row?.stockOutNum ?? row?.totalQuantity ?? row?.totalReturnNum ?? 0); |
| | | const un = Number(row?.unQuantity ?? 0); |
| | | if (!Number.isFinite(total) || !Number.isFinite(un)) return 0; |
| | | return Math.max(total - un, 0); |
| | | // 保留6位小数,避免浮点减法产生精度误差 |
| | | return Math.max(parseFloat((total - un).toFixed(6)), 0); |
| | | }; |
| | | |
| | | const tableColumn = ref([ |
| | |
| | | num, |
| | | returnQuantity: Number.isFinite(num) ? num : 0, |
| | | price: Number(raw?.taxInclusiveUnitPrice ?? raw?.price ?? 0), |
| | | amount: Number(raw?.amount ?? 0).toFixed(2), |
| | | amount: Number(raw?.amount ?? 0).toFixed(6), |
| | | isQuality: raw?.isQuality ?? 2, |
| | | remark: raw?.remark ?? "", |
| | | }; |
| | |
| | | const calculateRowAmount = (row) => { |
| | | const stockOutNum = Number(row.returnQuantity || 0); |
| | | const price = Number(row.price || 0); |
| | | row.amount = (stockOutNum * price).toFixed(2); |
| | | row.amount = (stockOutNum * price).toFixed(6); |
| | | }; |
| | | |
| | | const calculateTotalRefund = () => { |
| | | const total = tableData.value.reduce((sum, row) => { |
| | | return sum + Number(row.amount || 0); |
| | | }, 0); |
| | | form.value.refundAmount = total.toFixed(2); |
| | | form.value.refundAmount = total.toFixed(6); |
| | | }; |
| | | |
| | | const availableProducts = ref([]); |
| | |
| | | returnQuantity: 0, |
| | | num: 0, |
| | | price: Number(product.taxInclusiveUnitPrice ?? 0), |
| | | amount: "0.00", |
| | | amount: "0.000000", |
| | | isQuality: 2, |
| | | remark: "", |
| | | productCategory: product.productCategory ?? product.productName ?? "", |
| | |
| | | align="right" |
| | | > |
| | | <template #default="scope"> |
| | | {{ Number(scope.row.totalAmount ?? 0).toFixed(2) }} |
| | | {{ Number(scope.row.totalAmount ?? 0).toFixed(6) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="操作" width="120" align="center"> |
| | |
| | | :min="0" |
| | | v-model="productForm.taxInclusiveUnitPrice" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | :precision="6" |
| | | placeholder="请输入" |
| | | clearable |
| | | @change="calculateFromUnitPrice" |
| | |
| | | v-model="productForm.quantity" |
| | | placeholder="请输入" |
| | | clearable |
| | | :precision="2" |
| | | :precision="6" |
| | | @change="calculateFromQuantity" |
| | | style="width: 100%" |
| | | /> |
| | |
| | | v-model="scope.row.deliveryQuantity" |
| | | :min="0" |
| | | :max="getDeliveryBatchDeliveryMax(scope.row)" |
| | | :precision="2" |
| | | :precision="6" |
| | | :step="0.01" |
| | | controls-position="right" |
| | | @change="handleDeliveryBatchQuantityChange(scope.row)" |
| | |
| | | }; |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | if (cellValue === undefined || cellValue === null || cellValue === "") { |
| | | return "0.00"; |
| | | return "0.000000"; |
| | | } |
| | | return parseFloat(cellValue).toFixed(2); |
| | | return parseFloat(cellValue).toFixed(6); |
| | | }; |
| | | const findLedgerRecordByRow = (row) => { |
| | | if (!row) return null; |
| | |
| | | }; |
| | | // 主表合计方法 |
| | | const summarizeMainTable = (param) => { |
| | | return proxy.summarizeTable(param, [ |
| | | "contractAmount", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | ]); |
| | | return proxy.summarizeTable( |
| | | param, |
| | | ["contractAmount", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice"], |
| | | { |
| | | contractAmount: { decimalPlaces: 6 }, |
| | | taxInclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | taxExclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | } |
| | | ); |
| | | }; |
| | | // 子表合计方法 |
| | | const summarizeChildrenTable = (param, parentRow) => { |
| | |
| | | return ""; |
| | | }); |
| | | } |
| | | return proxy.summarizeTable(param, [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | ]); |
| | | return proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | ], |
| | | { |
| | | taxInclusiveUnitPrice: { decimalPlaces: 6 }, |
| | | taxInclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | taxExclusiveTotalPrice: { decimalPlaces: 6 }, |
| | | } |
| | | ); |
| | | }; |
| | | // 打开弹框 |
| | | const openForm = async (type, row) => { |
| | |
| | | const quantity = Number(p.quantity ?? 0) || 0; |
| | | const unitPrice = Number(p.unitPrice ?? 0) || 0; |
| | | const taxRate = "13"; // 默认 13%,便于直接提交(如需可在产品中自行修改) |
| | | const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(6); |
| | | const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( |
| | | taxInclusiveTotalPrice, |
| | | taxRate |
| | | taxRate, |
| | | 6 |
| | | ); |
| | | return { |
| | | // 台账字段 |
| | |
| | | unit: p.unit || "", |
| | | quantity: quantity, |
| | | taxRate: taxRate, |
| | | taxInclusiveUnitPrice: unitPrice.toFixed(2), |
| | | taxInclusiveUnitPrice: unitPrice.toFixed(6), |
| | | taxInclusiveTotalPrice: taxInclusiveTotalPrice, |
| | | taxExclusiveTotalPrice: taxExclusiveTotalPrice, |
| | | invoiceType: "增普票", |
| | |
| | | const total = products.reduce((sum, product) => { |
| | | return sum + (parseFloat(product.quantity) || 0); |
| | | }, 0); |
| | | return total.toFixed(2); |
| | | return total.toFixed(6); |
| | | }; |
| | | |
| | | // 计算产品总金额 |
| | |
| | | const total = products.reduce((sum, product) => { |
| | | return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0); |
| | | }, 0); |
| | | return total.toFixed(2); |
| | | return total.toFixed(6); |
| | | }; |
| | | |
| | | // 用于打印的计算函数 |
| | |
| | | const total = products.reduce((sum, product) => { |
| | | return sum + (parseFloat(product.quantity) || 0); |
| | | }, 0); |
| | | return total.toFixed(2); |
| | | return total.toFixed(6); |
| | | }; |
| | | |
| | | const getTotalAmountForPrint = (products) => { |
| | |
| | | const total = products.reduce((sum, product) => { |
| | | return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0); |
| | | }, 0); |
| | | return total.toFixed(2); |
| | | return total.toFixed(6); |
| | | }; |
| | | |
| | | const mathNum = () => { |
| | |
| | | productForm.value.taxInclusiveTotalPrice = |
| | | proxy.calculateTaxIncludeTotalPrice( |
| | | productForm.value.taxInclusiveUnitPrice, |
| | | productForm.value.quantity |
| | | productForm.value.quantity, |
| | | 6 |
| | | ); |
| | | if (productForm.value.taxRate) { |
| | | // 不含税总价计算 |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | productForm.value.taxInclusiveTotalPrice, |
| | | productForm.value.taxRate |
| | | productForm.value.taxRate, |
| | | 6 |
| | | ); |
| | | } |
| | | }; |
| | |
| | | isCalculating.value = true; |
| | | |
| | | // 计算含税单价 = 含税总价 / 数量 |
| | | productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2); |
| | | productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(6); |
| | | |
| | | // 如果有税率,计算不含税总价 |
| | | if (productForm.value.taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | totalPrice, |
| | | productForm.value.taxRate |
| | | productForm.value.taxRate, |
| | | 6 |
| | | ); |
| | | } |
| | | |
| | |
| | | // 先计算含税总价 = 不含税总价 / (1 - 税率/100) |
| | | const taxRateDecimal = taxRate / 100; |
| | | const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal); |
| | | productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2); |
| | | productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(6); |
| | | |
| | | // 计算含税单价 = 含税总价 / 数量 |
| | | productForm.value.taxInclusiveUnitPrice = ( |
| | | inclusiveTotalPrice / quantity |
| | | ).toFixed(2); |
| | | ).toFixed(6); |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | |
| | | isCalculating.value = true; |
| | | |
| | | // 计算含税总价 |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(6); |
| | | |
| | | // 如果有税率,计算不含税总价 |
| | | if (productForm.value.taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | productForm.value.taxInclusiveTotalPrice, |
| | | productForm.value.taxRate |
| | | productForm.value.taxRate, |
| | | 6 |
| | | ); |
| | | } |
| | | |
| | |
| | | isCalculating.value = true; |
| | | |
| | | // 计算含税总价 |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(6); |
| | | |
| | | // 如果有税率,计算不含税总价 |
| | | if (productForm.value.taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | productForm.value.taxInclusiveTotalPrice, |
| | | productForm.value.taxRate |
| | | productForm.value.taxRate, |
| | | 6 |
| | | ); |
| | | } |
| | | |
| | |
| | | |
| | | // 计算不含税总价 |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate); |
| | | proxy.calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate, 6); |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | |
| | | </el-table-column> |
| | | <el-table-column prop="totalAmount" label="报价金额" width="120"> |
| | | <template #default="scope"> |
| | | ¥{{ scope.row.totalAmount.toFixed(2) }} |
| | | ¥{{ scope.row.totalAmount.toFixed(6) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200" fixed="right" align="center"> |
| | |
| | | <el-table-column prop="unitPrice" label="单价"> |
| | | <template #default="scope"> |
| | | <el-form-item :prop="`products.${scope.$index}.unitPrice`" class="product-table-form-item"> |
| | | <el-input-number v-model="scope.row.unitPrice" :min="0" :precision="2" style="width: 100%" /> |
| | | <el-input-number v-model="scope.row.unitPrice" :min="0" :precision="6" style="width: 100%" /> |
| | | </el-form-item> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | <!-- <el-tag :type="getStatusType(currentQuotation.status)">{{ currentQuotation.status }}</el-tag>--> |
| | | <!-- </el-descriptions-item>--> |
| | | <el-descriptions-item label="报价总额" :span="2"> |
| | | <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">¥{{ currentQuotation.totalAmount?.toFixed(2) }}</span> |
| | | <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">¥{{ currentQuotation.totalAmount?.toFixed(6) }}</span> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | |
| | | <el-table-column prop="unit" label="单位" /> |
| | | <el-table-column prop="unitPrice" label="单价"> |
| | | <template #default="scope"> |
| | | ¥{{ scope.row.unitPrice.toFixed(2) }} |
| | | ¥{{ scope.row.unitPrice.toFixed(6) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </el-table-column>
|
| | | <el-table-column label="创建时间" align="center" prop="createTime" width="200">
|
| | | <template #default="scope">
|
| | | <span>{{ parseTime(scope.row.createTime) }}</span>
|
| | | <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
| | | </template>
|
| | | </el-table-column>
|
| | | <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
| | |
| | | <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
| | | <el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
| | | <template #default="scope">
|
| | | <span>{{ parseTime(scope.row.createTime) }}</span>
|
| | | <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
| | | </template>
|
| | | </el-table-column>
|
| | | <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
| | |
| | | <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
| | | <el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
| | | <template #default="scope">
|
| | | <span>{{ parseTime(scope.row.createTime) }}</span>
|
| | | <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
| | | </template>
|
| | | </el-table-column>
|
| | | <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
| | |
| | | </el-table-column>
|
| | | <el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
| | | <template #default="scope">
|
| | | <span>{{ parseTime(scope.row.createTime) }}</span>
|
| | | <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
| | | </template>
|
| | | </el-table-column>
|
| | | <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
|
| | |
| | | ></el-switch>
|
| | | </template>
|
| | | </el-table-column>
|
| | | <el-table-column label="创建时间" align="center" prop="createTime">
|
| | | <template #default="scope">
|
| | | <span>{{ parseTime(scope.row.createTime) }}</span>
|
| | | </template>
|
| | | </el-table-column>
|
| | | <el-table-column label="创建时间" align="center" prop="createTime">
|
| | | <template #default="scope">
|
| | | <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
| | | </template>
|
| | | </el-table-column> |
| | | <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
| | | <template #default="scope">
|
| | | <el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
|