feat:添加模具出库模块

master
黄伟杰 1 month ago
parent 3f17d6317f
commit e3dec8568e

@ -64,6 +64,14 @@ export function getMoldPage(params = {}) {
})
}
export function getMoldList(params = {}) {
return request({
url: '/admin-api/erp/mold-brand/mold/list',
method: 'get',
params
})
}
export function createMoldBrand(data) {
return request({
url: '/admin-api/erp/mold-brand/create',

@ -0,0 +1,63 @@
import request from '@/utils/request'
export function getMoldGetPage(params = {}) {
return request({
url: '/admin-api/erp/stock-out/page',
method: 'get',
params
})
}
export function getMoldGetDetail(id) {
return request({
url: '/admin-api/erp/stock-out/get',
method: 'get',
params: { id }
})
}
export function createMoldGet(data) {
return request({
url: '/admin-api/erp/stock-out/create',
method: 'post',
data
})
}
export function updateMoldGet(data) {
return request({
url: '/admin-api/erp/stock-out/update',
method: 'put',
data
})
}
export function updateMoldGetStatus(id, status) {
return request({
url: '/admin-api/erp/stock-out/update-status',
method: 'put',
params: { id, status }
})
}
export function deleteMoldGet(ids = []) {
return request({
url: '/admin-api/erp/stock-out/delete',
method: 'delete',
params: { ids: ids.join(',') }
})
}
export function getWarehouseSimpleList() {
return request({
url: '/admin-api/erp/warehouse/simple-list',
method: 'get'
})
}
export function getSimpleUserList() {
return request({
url: '/admin-api/system/user/simple-list',
method: 'get'
})
}

@ -91,6 +91,59 @@ const messages = {
yes: '是',
no: '否'
},
moldGet: {
moduleName: '模具出库',
subTitle: '按出库单号与状态快速筛选',
detailTitle: '模具出库详情',
basicInfo: '基础信息',
outNo: '出库单号',
outType: '出库类型',
outTime: '出库时间',
outTimeSingle: '出库日期',
outTimePlaceholder: '请选择出库日期',
warehouse: '仓库',
allWarehouse: '全部仓库',
warehousePlaceholder: '请选择仓库',
creator: '创建人',
status: '状态',
allStatus: '全部状态',
remark: '备注',
itemRemark: '明细备注',
attachment: '附件',
fileUrlPlaceholder: '请输入附件地址',
remarkPlaceholder: '请输入备注',
moldName: '模具',
moldCode: '模具编码',
moldStatus: '模具状态',
moldUseTime: '使用次数',
machineName: '使用设备',
isEnable: '是否启用',
createTime: '创建时间',
searchNo: '请输入出库单号',
searchMold: '请输入模具编码或名称',
searchCode: '请输入模具编码',
searchName: '请输入模具名称',
itemListTitle: '出库明细',
selectMold: '选择模具',
noItems: '暂无出库明细',
count: '数量',
noAuto: '系统自动生成',
createTitle: '新增模具出库',
editTitle: '编辑模具出库',
edit: '编辑',
delete: '删除',
approve: '审批',
empty: '暂无模具出库数据',
noMoldData: '暂无可选模具',
loadEditFailed: '加载编辑数据失败',
validatorOutTimeRequired: '出库日期不能为空',
validatorWarehouseRequired: '仓库不能为空',
validatorItemRequired: '请至少选择一个模具',
validatorCountRequired: '数量必须大于0',
confirmDelete: '确认删除出库单 {no} 吗?',
confirmApprove: '确认审批出库单 {no} 吗?',
approveSuccess: '审批成功'
},
mine: {
clickLogin: '点击登录',
username: '用户名:{name}',
@ -266,6 +319,59 @@ const messages = {
yes: 'Yes',
no: 'No'
},
moldGet: {
moduleName: 'Mold Stock-out',
subTitle: 'Filter quickly by no and status',
detailTitle: 'Mold Stock-out Detail',
basicInfo: 'Basic Info',
outNo: 'Stock-out No',
outType: 'Stock-out Type',
outTime: 'Stock-out Time',
outTimeSingle: 'Stock-out Date',
outTimePlaceholder: 'Select stock-out date',
warehouse: 'Warehouse',
allWarehouse: 'All Warehouses',
warehousePlaceholder: 'Select warehouse',
creator: 'Creator',
status: 'Status',
allStatus: 'All Status',
remark: 'Remark',
itemRemark: 'Item Remark',
attachment: 'Attachment',
fileUrlPlaceholder: 'Enter attachment URL',
remarkPlaceholder: 'Enter remark',
moldName: 'Mold',
moldCode: 'Mold Code',
moldStatus: 'Mold Status',
moldUseTime: 'Use Time',
machineName: 'Machine',
isEnable: 'Enabled',
createTime: 'Created At',
searchNo: 'Enter stock-out no',
searchMold: 'Enter mold code or name',
searchCode: 'Enter mold code',
searchName: 'Enter mold name',
itemListTitle: 'Item List',
selectMold: 'Select Mold',
noItems: 'No items',
count: 'Count',
noAuto: 'Generated automatically',
createTitle: 'Create Mold Stock-out',
editTitle: 'Edit Mold Stock-out',
edit: 'Edit',
delete: 'Delete',
approve: 'Approve',
empty: 'No mold stock-out data',
noMoldData: 'No mold options',
loadEditFailed: 'Failed to load edit data',
validatorOutTimeRequired: 'Stock-out date is required',
validatorWarehouseRequired: 'Warehouse is required',
validatorItemRequired: 'Select at least one mold',
validatorCountRequired: 'Count must be greater than 0',
confirmDelete: 'Delete stock-out {no}?',
confirmApprove: 'Approve stock-out {no}?',
approveSuccess: 'Approved successfully'
},
mine: {
clickLogin: 'Tap to sign in',
username: 'Username: {name}',
@ -409,7 +515,9 @@ const literalMap = {
'图片上传失败': 'functionCommon.uploadImageFailed',
'是': 'functionCommon.yes',
'否': 'functionCommon.no',
'暂无待办任务': 'dashboard.noTodo'
'暂无待办任务': 'dashboard.noTodo',
'模具出库': 'moldGet.moduleName',
'模具出库详情': 'moldGet.detailTitle'
}
function applyTabBarLanguage() {

@ -448,6 +448,20 @@
"navigationBarTitleText": "模具台账详情",
"navigationStyle": "custom"
}
},
{
"path": "moldget/index",
"style": {
"navigationBarTitleText": "模具出库",
"navigationStyle": "custom"
}
},
{
"path": "moldget/detail",
"style": {
"navigationBarTitleText": "模具出库详情",
"navigationStyle": "custom"
}
}
]
}

@ -233,11 +233,11 @@
</view>
<text class="function-name">模具台账</text>
</view>
<view class="function-item" @click="handleClick('模具出库')">
<view class="function-item" @click="handleClick('moldGet')">
<view class="function-icon" style="background: rgba(156, 39, 176, 0.1);">
<text class="icon-inner">📤</text>
</view>
<text class="function-name">模具出库</text>
<text class="function-name">{{ t('moldGet.moduleName') }}</text>
</view>
<view class="function-item" @click="handleClick('模具入库')">
<view class="function-icon" style="background: rgba(156, 39, 176, 0.1);">
@ -334,6 +334,9 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const scrollTop = ref(0);
const menuSearchKeyword = ref('');
@ -373,7 +376,7 @@ function handleClick(name) {
'设备关键件': '/pages_function/pages/equipmentKeypart/index',
'模具类型': '/pages_function/pages/moldType/index',
'模具台账': '/pages_function/pages/moldLedger/index',
'模具出库': '',
moldGet: '/pages_function/pages/moldget/index',
'模具入库': '',
'上下模': '',
'点检项库': '',

@ -0,0 +1,220 @@
<template>
<view class="page-container">
<view class="fixed-header">
<AppTitleHeader :title="t('moldGet.detailTitle')" />
</view>
<view class="content-section">
<view class="info-card">
<view class="card-title">{{ t('moldGet.basicInfo') }}</view>
<view class="info-list">
<view class="info-row">
<text class="info-label">{{ t('moldGet.outNo') }}</text>
<text class="info-value">{{ textValue(detail.no) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldGet.outType') }}</text>
<text class="info-value">{{ textValue(detail.outType) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldGet.outTime') }}</text>
<text class="info-value">{{ dateTimeLabel(detail.outTime) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldGet.warehouse') }}</text>
<text class="info-value">{{ textValue(detail.warehouseName) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldGet.creator') }}</text>
<text class="info-value">{{ textValue(detail.creatorName) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldGet.status') }}</text>
<text class="info-value">{{ statusLabel(detail.status) }}</text>
</view>
<view class="info-row remark-row">
<text class="info-label">{{ t('moldGet.remark') }}</text>
<text class="info-value remark-value">{{ textValue(detail.remark) }}</text>
</view>
</view>
</view>
<view class="tabs-card">
<u-tabs :list="tabList" :current="currentTab" :is-scroll="false" activeColor="#1a3a5c" @change="onTabChange" />
<view v-if="currentTab === 0" class="item-wrap">
<view v-if="!items.length" class="empty">{{ t('moldGet.noItems') }}</view>
<view v-for="(item, index) in items" :key="index" class="item-card">
<view class="item-head">{{ textValue(item.productName) }}</view>
<view class="item-row">
<text class="item-label">{{ t('moldGet.moldCode') }}</text>
<text class="item-value">{{ textValue(item.productCode || item.productBarCode) }}</text>
</view>
<view class="item-row">
<text class="item-label">{{ t('moldGet.count') }}</text>
<text class="item-value">{{ textValue(item.count) }}</text>
</view>
<view class="item-row">
<text class="item-label">{{ t('moldGet.itemRemark') }}</text>
<text class="item-value">{{ textValue(item.remark) }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import AppTitleHeader from '@/components/common/AppTitleHeader.vue'
import { getMoldGetDetail } from '@/api/mes/moldget'
import { useDict } from '@/utils/dict'
const { t } = useI18n()
const { erp_audit_status } = useDict('erp_audit_status')
const detail = ref({})
const items = ref([])
const currentTab = ref(0)
const tabList = ref([{ name: t('moldGet.itemListTitle') }])
function textValue(v) {
if (v === 0) return '0'
if (v === null || v === undefined) return '-'
const s = String(v).trim()
return s || '-'
}
function dateTimeLabel(v) {
if (!v) return '-'
const d = new Date(Number(v))
if (Number.isNaN(d.getTime())) return textValue(v)
const p = (n) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`
}
function statusLabel(status) {
const hit = (erp_audit_status.value || []).find((s) => String(s.value) === String(status))
return hit ? hit.label : textValue(status)
}
function onTabChange(e) {
const idx = e && typeof e === 'object' ? e.index : e
currentTab.value = Number(idx || 0)
}
async function loadDetail(id) {
const res = await getMoldGetDetail(id)
const data = res?.data || {}
detail.value = data
items.value = Array.isArray(data.items) ? data.items : []
}
onLoad(async (query) => {
const id = query?.id
if (!id) {
uni.showToast({ title: t('functionCommon.noIdView'), icon: 'none' })
return
}
try {
await loadDetail(id)
} catch (e) {
uni.showToast({ title: t('functionCommon.loadFailed'), icon: 'none' })
}
})
</script>
<style lang="scss" scoped>
.page-container {
min-height: 100vh;
background: #f0f2f5;
}
.fixed-header {
position: sticky;
top: 0;
z-index: 20;
}
.content-section {
padding: 0 24rpx 24rpx;
}
.info-card,
.tabs-card {
margin-top: 20rpx;
background: #fff;
border-radius: 20rpx;
padding: 28rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.tabs-card {
margin-bottom: 16rpx;
}
.card-title {
font-size: 32rpx;
color: #1a3a5c;
font-weight: 700;
margin-bottom: 18rpx;
}
.info-list {
background: #ffffff;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 18rpx 0;
border-bottom: 1rpx solid #edf0f3;
}
.info-label {
font-size: 27rpx;
color: #8a9099;
width: 220rpx;
}
.info-value {
flex: 1;
text-align: right;
font-size: 28rpx;
color: #303133;
line-height: 1.45;
}
.remark-row {
border-bottom: none;
}
.remark-value {
white-space: pre-wrap;
}
.item-wrap {
margin-top: 18rpx;
}
.item-card {
background: #f8fafc;
border-radius: 12rpx;
padding: 16rpx;
margin-bottom: 12rpx;
}
.item-head {
font-size: 26rpx;
color: #1a3a5c;
font-weight: 700;
}
.item-row {
margin-top: 10rpx;
display: flex;
justify-content: space-between;
}
.item-label {
color: #909399;
font-size: 22rpx;
}
.item-value {
color: #303133;
font-size: 22rpx;
max-width: 65%;
text-align: right;
}
.empty {
text-align: center;
color: #909399;
padding: 24rpx 0;
}
</style>

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save