2 Commits

Author SHA1 Message Date
6c5722c47c 采购需求增加"是否发往车间"及发货地址字段
表单新增单选,选"否"时需填写发货地址;列表新增对应列。已在生产库
oa_requirements 表执行 ADD COLUMN 迁移。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 14:24:32 +08:00
598f88b03a 报销/拨款发票明细增加预览功能
审核员点击发票明细行的"预览"按钮即可直接查看PDF/图片内容,复用已有的
Folder全局预览组件,无需下载。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 14:24:08 +08:00
8 changed files with 129 additions and 14 deletions

View File

@@ -49,6 +49,14 @@ public class OaRequirements extends BaseEntity {
* 关联物料 ID CSV -> sys_oa_warehouse.id可选
*/
private String materialIds;
/**
* 是否发往车间1是0否
*/
private Integer shipToWorkshop;
/**
* 发货地址(是否发往车间=否时必填)
*/
private String shipAddress;
/**
* 需求描述
*/

View File

@@ -54,6 +54,16 @@ public class OaRequirementsBo extends BaseEntity {
*/
private String materialIds;
/**
* 是否发往车间1是0否
*/
private Integer shipToWorkshop;
/**
* 发货地址(是否发往车间=否时必填)
*/
private String shipAddress;
/**
* 需求描述
*/

View File

@@ -91,6 +91,14 @@ public class OaRequirementsVo extends BaseEntity {
/** 关联物料 ID CSV */
private String materialIds;
/** 是否发往车间1是0否 */
@ExcelProperty(value = "是否发往车间")
private Integer shipToWorkshop;
/** 发货地址(是否发往车间=否时必填) */
@ExcelProperty(value = "发货地址")
private String shipAddress;
/** 关联物料明细service 层 enrich列表/详情都返回) */
private java.util.List<MaterialItem> materials;

View File

@@ -10,6 +10,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="requesterId" column="requester_id"/>
<result property="ownerId" column="owner_id"/>
<result property="projectId" column="project_id"/>
<result property="shipToWorkshop" column="ship_to_workshop"/>
<result property="shipAddress" column="ship_address"/>
<result property="description" column="description"/>
<result property="deadline" column="deadline"/>
<result property="status" column="status"/>

View File

@@ -35,14 +35,20 @@
<el-table-column prop="amount" label="金额(元)" width="110" align="right">
<template slot-scope="{ row }">¥{{ row.amount }}</template>
</el-table-column>
<el-table-column label="附件" width="80" align="center">
<el-table-column label="附件" width="130" align="center">
<template slot-scope="scope">
<el-button
v-if="scope.row.ossId && isFirstRowOfFile(detail.invoiceItems, scope.$index, scope.row.ossId)"
type="text" size="mini" title="下载附件"
@click="downloadOss(scope.row.ossId)">
<i class="el-icon-download"></i> 下载
</el-button>
<template v-if="scope.row.ossId && isFirstRowOfFile(detail.invoiceItems, scope.$index, scope.row.ossId)">
<el-button
type="text" size="mini" title="预览附件"
@click="previewOss(scope.row.ossId)">
<i class="el-icon-view"></i> 预览
</el-button>
<el-button
type="text" size="mini" title="下载附件"
@click="downloadOss(scope.row.ossId)">
<i class="el-icon-download"></i> 下载
</el-button>
</template>
</template>
</el-table-column>
</el-table>
@@ -92,6 +98,7 @@ export default {
FilePreview,
BizDetailContainer
},
inject: ['$folder'],
data () {
return {
loading: false,
@@ -357,6 +364,20 @@ export default {
downloadOss (ossId) {
this.$download.oss(ossId)
},
async previewOss (ossId) {
try {
const res = await listByIds([ossId])
const file = (res.data || [])[0]
if (!file) {
this.$message.warning('文件不存在')
return
}
this.$folder().previewSimple(file)
} catch (e) {
console.error('预览失败:', e)
this.$message.error('预览失败')
}
},
getActionText (action) {
const map = {
'submit': '提交申请',

View File

@@ -26,14 +26,20 @@
<el-table-column prop="amount" label="金额(元)" width="110" align="right">
<template slot-scope="{ row }">¥{{ row.amount }}</template>
</el-table-column>
<el-table-column label="附件" width="80" align="center">
<el-table-column label="附件" width="130" align="center">
<template slot-scope="scope">
<el-button
v-if="scope.row.ossId && isFirstRowOfFile(detail.invoiceItems, scope.$index, scope.row.ossId)"
type="text" size="mini" title="下载附件"
@click="downloadOss(scope.row.ossId)">
<i class="el-icon-download"></i> 下载
</el-button>
<template v-if="scope.row.ossId && isFirstRowOfFile(detail.invoiceItems, scope.$index, scope.row.ossId)">
<el-button
type="text" size="mini" title="预览附件"
@click="previewOss(scope.row.ossId)">
<i class="el-icon-view"></i> 预览
</el-button>
<el-button
type="text" size="mini" title="下载附件"
@click="downloadOss(scope.row.ossId)">
<i class="el-icon-download"></i> 下载
</el-button>
</template>
</template>
</el-table-column>
</el-table>
@@ -66,6 +72,7 @@
</template>
<script>
import { listByIds } from "@/api/system/oss";
import FilePreview from "@/components/FilePreview/index.vue";
import BizDetailContainer from '@/views/hrm/components/BizDetailContainer/index.vue';
@@ -80,6 +87,7 @@ export default {
BizDetailContainer,
FilePreview
},
inject: ['$folder'],
computed: {
currentBizId () {
return this.bizId || this.$route?.params?.bizId || this.$route?.query?.bizId || this.$route?.params?.id
@@ -97,6 +105,20 @@ export default {
},
downloadOss (ossId) {
this.$download.oss(ossId)
},
async previewOss (ossId) {
try {
const res = await listByIds([ossId])
const file = (res.data || [])[0]
if (!file) {
this.$message.warning('文件不存在')
return
}
this.$folder().previewSimple(file)
} catch (e) {
console.error('预览失败:', e)
this.$message.error('预览失败')
}
}
}
}

View File

@@ -106,6 +106,15 @@
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="是否发往车间" align="center" width="110">
<template slot-scope="{ row }">
<el-tag v-if="row.shipToWorkshop === 0" type="warning" size="mini"></el-tag>
<el-tag v-else type="success" size="mini"></el-tag>
<div v-if="row.shipToWorkshop === 0 && row.shipAddress" class="ship-address">
{{ row.shipAddress }}
</div>
</template>
</el-table-column>
<el-table-column label="采购物料" align="left" min-width="170">
<template slot-scope="{ row }">
<template v-if="row.materials && row.materials.length">
@@ -215,6 +224,15 @@
</div>
</div>
</el-form-item>
<el-form-item label="是否发往车间" prop="shipToWorkshop">
<el-radio-group v-model="form.shipToWorkshop">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.shipToWorkshop === 0" label="发货地址" prop="shipAddress">
<el-input v-model="form.shipAddress" placeholder="请输入发货地址" />
</el-form-item>
<el-form-item label="需求描述" prop="description">
<el-input v-model="form.description" type="textarea" placeholder="请输入需求描述" />
</el-form-item>
@@ -321,6 +339,8 @@
<el-descriptions-item label="需求方">{{ detailRow.requesterNickName }}</el-descriptions-item>
<el-descriptions-item label="负责人">{{ detailRow.ownerNickName }}</el-descriptions-item>
<el-descriptions-item label="关联项目">{{ detailRow.projectName }}</el-descriptions-item>
<el-descriptions-item label="是否发往车间">{{ detailRow.shipToWorkshop === 0 ? '否' : '是' }}</el-descriptions-item>
<el-descriptions-item v-if="detailRow.shipToWorkshop === 0" label="发货地址">{{ detailRow.shipAddress }}</el-descriptions-item>
<el-descriptions-item label="需求描述">{{ detailRow.description }}</el-descriptions-item>
<el-descriptions-item label="截止日期">{{ detailRow.deadline }}</el-descriptions-item>
<el-descriptions-item label="剩余时间">{{ getRemainText(detailRow.deadline) }}</el-descriptions-item>
@@ -445,6 +465,18 @@ export default {
],
deadline: [
{ required: true, message: "请选择截止日期", trigger: "change" }
],
shipAddress: [
{
validator: (rule, value, callback) => {
if (this.form.shipToWorkshop === 0 && !value) {
callback(new Error("请输入发货地址"));
} else {
callback();
}
},
trigger: "blur"
}
]
},
detailDialog: false,
@@ -688,6 +720,8 @@ export default {
projectId: undefined,
materialIds: undefined,
materialIdArr: [],
shipToWorkshop: 1,
shipAddress: undefined,
description: undefined,
deadline: undefined,
status: 0,
@@ -978,6 +1012,12 @@ export default {
}
.mat-stock-meta { color: #909399; }
}
.ship-address {
margin-top: 4px;
font-size: 11px;
color: #909399;
word-break: break-all;
}
.accessory-link {
display: inline-block;
max-width: 160px;

View File

@@ -0,0 +1,4 @@
-- 采购需求增加"是否发往车间"及"发货地址"
ALTER TABLE oa_requirements
ADD COLUMN ship_to_workshop TINYINT(1) DEFAULT 1 COMMENT '是否发往车间1是0否' AFTER material_ids,
ADD COLUMN ship_address VARCHAR(255) DEFAULT NULL COMMENT '发货地址(是否发往车间=否时必填)' AFTER ship_to_workshop;