feat: 基础信息弹窗新增"发起采购申请"按钮, 跳转采购管理自动预填物料+默认审批人

- material/list.vue: 弹窗头部新增"发起采购申请"按钮, 携带物料信息跳转/purchase
- purchase/index.vue: onMounted读取URL参数自动弹窗并预填物料
- purchase/index.vue: fetchDefaultApprover取当前用户上一次采购申请的审批人作为默认值
- 商家链接placeholder去掉"选填"字样
This commit is contained in:
yueli
2026-07-14 17:13:31 +08:00
parent 68fd93b457
commit 31903bdb39
2 changed files with 80 additions and 7 deletions

View File

@ -405,6 +405,15 @@
> >
<el-icon style="margin-right: 4px"><Plus /></el-icon>加入或查看BOM <el-icon style="margin-right: 4px"><Plus /></el-icon>加入或查看BOM
</el-link> </el-link>
<el-link
v-if="form.id"
type="warning"
:underline="false"
style="font-size: 14px;"
@click="createPurchaseForMaterial"
>
<el-icon style="margin-right: 4px"><ShoppingCart /></el-icon>发起采购申请
</el-link>
</div> </div>
</div> </div>
</template> </template>
@ -696,7 +705,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue'; import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
import { Plus, Document, DocumentCopy, Refresh, Setting, Rank, Camera, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture } from '@element-plus/icons-vue'; import { Plus, Document, DocumentCopy, Refresh, Setting, Rank, Camera, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture, ShoppingCart } from '@element-plus/icons-vue';
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'; import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import type { FormInstance, FormRules } from 'element-plus'; import type { FormInstance, FormRules } from 'element-plus';
import { useUserStore } from '@/stores/user'; import { useUserStore } from '@/stores/user';
@ -1561,6 +1570,22 @@ const createBomForMaterial = () => {
window.open(routeUrl.href, '_blank'); window.open(routeUrl.href, '_blank');
}; };
const createPurchaseForMaterial = () => {
if (!form.value.id) {
return ElMessage.warning('请先保存物料基础信息后再操作');
}
const routeUrl = router.resolve({
path: '/purchase',
query: {
material_id: String(form.value.id),
name: form.value.name,
spec: form.value.spec,
unit: form.value.unit
}
});
window.open(routeUrl.href, '_blank');
};
const resetForm = () => { const resetForm = () => {
form.value = JSON.parse(JSON.stringify(initForm)); form.value = JSON.parse(JSON.stringify(initForm));
fileListImage.value = []; fileListImage.value = [];

View File

@ -138,7 +138,7 @@
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="商家链接"> <el-form-item label="商家链接">
<el-input v-model="form.supplier_link" placeholder="商家地址链接(选填)" clearable /> <el-input v-model="form.supplier_link" placeholder="商家地址链接" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
@ -235,6 +235,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { Refresh, Plus } from '@element-plus/icons-vue' import { Refresh, Plus } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
@ -372,21 +373,55 @@ const handlePageChange = (p: number) => { page.value = p; fetchData() }
const handleSizeChange = (s: number) => { pageSize.value = s; page.value = 1; fetchData() } const handleSizeChange = (s: number) => { pageSize.value = s; page.value = 1; fetchData() }
// --- 新建 --- // --- 新建 ---
const openCreateDialog = () => { const openCreateDialog = (prefill?: { materialId?: number; name?: string; spec?: string; unit?: string }) => {
dialogTitle.value = '新建采购申请' dialogTitle.value = '新建采购申请'
form.value = { form.value = {
name: '', spec_model: '', quantity: 1, name: prefill?.name || '',
spec_model: prefill?.spec || '',
quantity: 1,
purchase_date: new Date().toISOString().split('T')[0], purchase_date: new Date().toISOString().split('T')[0],
supplier_link: '', remark: '', supplier_link: '', remark: '',
unit_price: undefined, total_price: undefined, unit_price: undefined, total_price: undefined,
approver_id: undefined, images: [] approver_id: undefined, images: []
} }
materialBaseId.value = null
materialOptions.value = [] if (prefill?.materialId) {
autoFillHint.value = '' materialBaseId.value = prefill.materialId
// 预填物料选项以便显示选中状态
materialOptions.value = [{
id: prefill.materialId,
name: prefill.name || '',
spec_model: prefill.spec || ''
}]
if (prefill.spec) {
form.value.spec_model = prefill.spec
}
autoFillHint.value = `已从基础信息【${prefill.name || ''}】带入,请补充采购信息`
} else {
materialBaseId.value = null
materialOptions.value = []
autoFillHint.value = ''
}
fileList.value = [] fileList.value = []
totalPriceManuallyEdited.value = false totalPriceManuallyEdited.value = false
formDialogVisible.value = true formDialogVisible.value = true
// 异步加载默认审批人(取当前用户上一次采购申请的审批人)
fetchDefaultApprover()
}
// 获取当前用户上一次采购申请的审批人作为默认值
const fetchDefaultApprover = async () => {
try {
const res: any = await getPurchaseList({ page: 1, limit: 1, status: undefined })
const items = res?.data?.items || []
if (items.length > 0 && items[0].approver_id) {
form.value.approver_id = items[0].approver_id
}
} catch (e) {
// 静默失败,用户可手动选择
}
} }
// --- 物料搜索(分页) --- // --- 物料搜索(分页) ---
@ -602,9 +637,22 @@ const confirmReject = async () => {
} }
// --- 初始化 --- // --- 初始化 ---
const route = useRoute()
onMounted(() => { onMounted(() => {
fetchData() fetchData()
fetchApprovers() fetchApprovers()
// 从基础信息跳转过来的参数
const query = route.query
if (query.material_id) {
openCreateDialog({
materialId: Number(query.material_id),
name: (query.name as string) || '',
spec: (query.spec as string) || '',
unit: (query.unit as string) || ''
})
}
}) })
</script> </script>