| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583 |
- <template>
- <uni-navbar-lite :showRight=false title="创建采购单"></uni-navbar-lite>
- <view class="page-container">
- <scroll-view class="page-content" scroll-y="true">
- <view v-if="applyList.length === 0" class="empty-tip">
- <text class="empty-tip-text">暂无申请单数据</text>
- </view>
-
- <view v-else>
- <view class="purchase-info-section">
- <view class="purchase-info-row">
- <text class="purchase-info-label">采购单名称</text>
- <view class="purchase-info-value-wrap">
- <input
- class="purchase-info-input"
- v-model="purchaseName"
- placeholder="请输入采购单名称"
- />
- </view>
- </view>
- <view class="purchase-remark-section">
- <text class="purchase-remark-label">采购单备注</text>
- <textarea
- class="purchase-remark-input"
- placeholder="请输入采购单备注"
- v-model="purchaseRemark"
- :maxlength="500"
- ></textarea>
- </view>
- </view>
- <view v-for="(apply, applyIndex) in applyList" :key="applyIndex" class="section">
- <view class="section-header">
- <view class="section-indicator"></view>
- <text class="section-title">申请单 {{ apply.applyCode }}</text>
- </view>
- <view class="info-card">
- <view class="info-row">
- <text class="info-label">申请人</text>
- <text class="info-value">{{ apply.nickName }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">申请时间</text>
- <text class="info-value">{{ apply.createTime }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">用途</text>
- <text class="info-value">{{ apply.remark }}</text>
- </view>
- </view>
- <view class="material-section">
- <view class="material-section-header">
- <text class="material-section-title">物料明细</text>
- </view>
- <view class="material-list">
- <view
- v-for="(item, itemIndex) in apply.lineList"
- :key="itemIndex"
- class="material-item"
- >
- <view class="material-info">
- <text class="material-name">{{ getItemName(item) }}</text>
- <text class="material-spec" v-if="getSpecification(item)">规格:{{ getSpecification(item) }}</text>
- </view>
- <view class="material-detail">
- <view class="detail-row">
- <text class="detail-label">申请数量</text>
- <text class="detail-value">{{ getQuantity(item) }} {{ getMeasureName(item) }}</text>
- </view>
- <view class="detail-row purchase-row">
- <text class="detail-label">采购数量</text>
- <view class="purchase-input-wrap">
- <input
- class="purchase-input"
- type="number"
- v-model="item.purchaseQty"
- @input="handlePurchaseQtyChange"
- />
- <text class="purchase-unit">{{ getMeasureName(item) }}</text>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- <view class="bottom-space"></view>
- </scroll-view>
- <view class="bottom-buttons">
- <button class="submit-btn" @click="handleSubmit">生成采购单</button>
- </view>
- </view>
- </template>
- <script setup lang="uts">
- import { ref } from 'vue'
- import { getPurchaseApplyById } from '../../api/apply/index'
- import { createMergePurchase } from '../../api/purchase/index'
- import { getUserInfo } from '../../utils/storage'
- const applyIds = ref<string>("")
- const idList = ref<string[]>([])
- const applyList = ref<UTSJSONObject[]>([])
- const loading = ref<boolean>(false)
- const purchaseName = ref<string>("")
- const purchaseRemark = ref<string>("")
- const currentUserId = ref<string>("")
- const getItemName = (item: UTSJSONObject): string => {
- if (item == null) return ''
- const val = item['itemName']
- return val != null ? val.toString() : ''
- }
- const getSpecification = (item: UTSJSONObject): string => {
- if (item == null) return ''
- const val = item['specification']
- return val != null ? val.toString() : ''
- }
- const getQuantity = (item: UTSJSONObject): string => {
- if (item == null) return '0'
- const val = item['quantityApply']
- return val != null ? val.toString() : '0'
- }
- const getMeasureName = (item: UTSJSONObject): string => {
- if (item == null) return ''
- const val = item['measureName']
- return val != null ? val.toString() : ''
- }
- const handlePurchaseQtyChange = (): void => {
- }
- const loadApplyDetails = (): void => {
- if (idList.value.length === 0) return
- loading.value = true
-
- const promises = idList.value.map((id) => {
- return getPurchaseApplyById(id)
- })
- Promise.all(promises).then((responses: any[]) => {
- const resultList: UTSJSONObject[] = []
- responses.forEach((response: any) => {
- const res = response as UTSJSONObject
- const data = res["data"] as UTSJSONObject
- const apply = new UTSJSONObject()
- apply['applyId'] = data['applyId'] != null ? parseInt(data['applyId'].toString()) : 0
- apply['applyCode'] = data['applyCode'] != null ? data['applyCode'].toString() : ''
- apply['nickName'] = data['nickName'] != null ? data['nickName'].toString() : ''
- apply['createTime'] = data['createTime'] != null ? data['createTime'].toString() : ''
- apply['remark'] = data['remark'] != null ? data['remark'].toString() : ''
- apply['applyUser'] = data['applyUser'] != null ? data['applyUser'].toString() : ''
- apply['applyUserId'] = data['applyUserId'] != null ? parseInt(data['applyUserId'].toString()) : 0
- apply['applyDeptName'] = data['applyDeptName'] != null ? data['applyDeptName'].toString() : ''
-
- const lines = data['wmPurchaseApplyLineList']
- const lineList: UTSJSONObject[] = []
- if (lines != null) {
- (lines as UTSJSONObject[]).forEach((line: UTSJSONObject) => {
- const lineItem = new UTSJSONObject()
- lineItem['lineId'] = line['id'] != null ? line['id'].toString() : ''
- lineItem['itemId'] = line['itemId'] != null ? line['itemId'].toString() : ''
- lineItem['itemCode'] = line['itemCode'] != null ? line['itemCode'].toString() : ''
- lineItem['itemName'] = line['itemName'] != null ? line['itemName'].toString() : ''
- lineItem['specification'] = line['specification'] != null ? line['specification'].toString() : ''
- lineItem['unitOfMeasure'] = line['unitOfMeasure'] != null ? line['unitOfMeasure'].toString() : ''
- lineItem['measureName'] = line['measureName'] != null ? line['measureName'].toString() : ''
- lineItem['quantityApply'] = line['quantityApply'] != null ? line['quantityApply'] : 0
- lineItem['purchaseQty'] = line['quantityApply'] != null ? line['quantityApply'].toString() : '0'
- lineList.push(lineItem)
- })
- }
- apply['lineList'] = lineList
- resultList.push(apply)
- })
- applyList.value = resultList
- loading.value = false
- generatePurchaseName()
- }).catch((e) => {
- console.error('加载申请单详情失败:', e)
- loading.value = false
- uni.showToast({ title: '加载失败', icon: 'none' })
- })
- }
- const generatePurchaseName = (): void => {
- if (applyList.value.length === 0) {
- purchaseName.value = ''
- return
- }
- const now = new Date()
- const year = now.getFullYear()
- const month = String(now.getMonth() + 1).padStart(2, '0')
- const day = String(now.getDate()).padStart(2, '0')
- const hours = String(now.getHours()).padStart(2, '0')
- const minutes = String(now.getMinutes()).padStart(2, '0')
- const seconds = String(now.getSeconds()).padStart(2, '0')
-
- const dateStr = `${year}${month}${day}${hours}${minutes}${seconds}`
- const applicants = new Set<string>()
- applyList.value.forEach((apply) => {
- const name = apply['nickName']
- if (name != null && name.toString().length > 0) {
- applicants.add(name.toString())
- }
- })
- const applicantStr = Array.from(applicants).join(',')
- purchaseName.value = `${dateStr}-${applicantStr}`
- }
- const handleSubmit = (): void => {
- const purchaseData = new UTSJSONObject()
- const mergedItems: UTSJSONObject[] = []
-
- let totalQuantity = 0
-
- applyList.value.forEach((apply) => {
- const applyId = apply['applyId']
- const applyRemark = apply['remark'] != null ? apply['remark'].toString() : ''
- const applyUser = apply['applyUser'] != null ? apply['applyUser'].toString() : ''
- const applyUserId = apply['applyUserId']
- const applyDeptName = apply['applyDeptName'] != null ? apply['applyDeptName'].toString() : ''
- const lineList = apply['lineList'] as UTSJSONObject[]
- lineList.forEach((item) => {
- const qty = parseInt(item['purchaseQty'])
- if (qty > 0 && qty <= parseInt(getQuantity(item))) {
- const lineItem = new UTSJSONObject()
- lineItem['applyId'] = applyId
- lineItem['applyLineId'] = parseInt(item['lineId'])
- lineItem['itemId'] = parseInt(item['itemId'])
- lineItem['itemCode'] = item['itemCode'] != null ? item['itemCode'].toString() : ''
- lineItem['itemName'] = item['itemName'] != null ? item['itemName'].toString() : ''
- lineItem['specification'] = item['specification'] != null ? item['specification'].toString() : ''
- lineItem['unitOfMeasure'] = item['unitOfMeasure'] != null ? item['unitOfMeasure'].toString() : ''
- lineItem['measureName'] = item['measureName'] != null ? item['measureName'].toString() : ''
- lineItem['quantityApply'] = parseInt(getQuantity(item))
- lineItem['quantityPurchase'] = qty
- lineItem['applyRemark'] = applyRemark
- lineItem['applyUser'] = applyUser
- lineItem['applyUserId'] = applyUserId
- lineItem['applyDeptName'] = applyDeptName
- mergedItems.push(lineItem)
- totalQuantity += qty
- }
- })
- })
- if (mergedItems.length === 0) {
- uni.showToast({ title: '请填写有效的采购数量', icon: 'none' })
- return
- }
- const mergePurchase = new UTSJSONObject()
- mergePurchase['mergeName'] = purchaseName.value
- mergePurchase['remark'] = purchaseRemark.value
- mergePurchase['totalQuantity'] = totalQuantity
- purchaseData['mergePurchase'] = mergePurchase
- purchaseData['applyUserId'] = currentUserId.value.length > 0 ? parseInt(currentUserId.value) : 0
- purchaseData['applyIds'] = idList.value.map(id => parseInt(id))
- purchaseData['mergedItems'] = mergedItems
- purchaseData['platform'] = 'mobile'
- uni.showModal({
- title: '提示',
- content: '确定生成采购单吗?',
- success: (res) => {
- if (res.confirm) {
- uni.showLoading({ title: '生成中...' })
- createMergePurchase(purchaseData).then((response: any) => {
- uni.hideLoading()
- const result = response as UTSJSONObject
- if (result['code'] === 200) {
- uni.showToast({ title: '生成成功', icon: 'success' })
- setTimeout(() => {
- uni.redirectTo({
- url: '/pages/apply/index?refresh=1'
- })
- }, 1500)
- } else {
- const msg = result['msg'] != null ? result['msg'].toString() : '生成失败'
- uni.showToast({ title: msg, icon: 'none' })
- }
- }).catch((e) => {
- uni.hideLoading()
- const error = e as UTSError
- const errMsg = error?.message
- uni.showToast({ title: errMsg != null ? errMsg.toString() : '生成失败', icon: 'none' })
- })
- }
- }
- })
- }
- onLoad((options: any) => {
- const userInfo = getUserInfo()
- if (userInfo != null) {
- const userId = userInfo['userId']
- currentUserId.value = userId != null ? userId.toString() : ''
- }
-
- const params = options as UTSJSONObject
- if (params != null && params['applyIds'] != null) {
- applyIds.value = params['applyIds'].toString()
- idList.value = applyIds.value.split(',').filter((id: string) => id.trim().length > 0)
- loadApplyDetails()
- }
- })
- </script>
- <style lang="scss">
- .page-container {
- flex: 1;
- background-color: #e8f0f9;
- }
- .page-content {
- flex: 1;
- padding: 20rpx;
- padding-bottom: 140rpx;
- }
- .purchase-info-section {
- margin-bottom: 20rpx;
- background: #ffffff;
- border-radius: 16rpx;
- padding: 20rpx;
- }
- .purchase-info-row {
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20rpx;
- }
- .purchase-info-label {
- font-size: 28rpx;
- color: #666666;
- }
- .purchase-info-value-wrap {
- flex: 1;
- margin-left: 20rpx;
- background-color: #f8f9fa;
- border-radius: 8rpx;
- padding: 12rpx 16rpx;
- }
- .purchase-info-value {
- font-size: 28rpx;
- color: #333333;
- font-weight: bold;
- }
- .purchase-info-input {
- font-size: 28rpx;
- color: #333333;
- width: 100%;
- background-color: transparent;
- }
- .purchase-remark-section {
- margin-top: 16rpx;
- }
- .purchase-remark-label {
- font-size: 28rpx;
- color: #666666;
- margin-bottom: 12rpx;
- display: block;
- }
- .purchase-remark-input {
- width: 100%;
- min-height: 160rpx;
- background-color: #f8f9fa;
- border-radius: 8rpx;
- padding: 16rpx;
- font-size: 28rpx;
- color: #333333;
- box-sizing: border-box;
- }
- .section {
- margin-bottom: 20rpx;
- background: #ffffff;
- border-radius: 16rpx;
- padding: 20rpx;
- }
- .section-header {
- flex-direction: row;
- align-items: center;
- margin-bottom: 20rpx;
- }
- .section-indicator {
- width: 6rpx;
- height: 32rpx;
- background-color: #007aff;
- border-radius: 3rpx;
- margin-right: 12rpx;
- }
- .section-title {
- font-size: 32rpx;
- color: #333333;
- font-weight: bold;
- }
- .info-card {
- background-color: #f8f9fa;
- border-radius: 8rpx;
- padding: 20rpx;
- margin-bottom: 20rpx;
- }
- .info-row {
- flex-direction: row;
- justify-content: space-between;
- margin-bottom: 16rpx;
- &:last-child {
- margin-bottom: 0;
- }
- }
- .info-label {
- font-size: 28rpx;
- color: #666666;
- }
- .info-value {
- font-size: 28rpx;
- color: #333333;
- }
- .material-section {
- background-color: #f8f9fa;
- border-radius: 8rpx;
- padding: 20rpx;
- }
- .material-section-header {
- margin-bottom: 16rpx;
- }
- .material-section-title {
- font-size: 28rpx;
- color: #333333;
- font-weight: bold;
- }
- .material-list {
- background-color: #ffffff;
- border-radius: 8rpx;
- padding: 16rpx;
- }
- .material-item {
- padding: 16rpx 0;
- border-bottom: 1rpx solid #f0f0f0;
- &:last-child {
- border-bottom: none;
- }
- }
- .material-info {
- margin-bottom: 12rpx;
- }
- .material-name {
- font-size: 28rpx;
- color: #333333;
- font-weight: bold;
- display: block;
- }
- .material-spec {
- font-size: 24rpx;
- color: #999999;
- margin-top: 4rpx;
- display: block;
- }
- .material-detail {
- flex-direction: row;
- flex-wrap: wrap;
- }
- .detail-row {
- flex-direction: row;
- width: 50%;
- align-items: center;
- margin-bottom: 8rpx;
- }
- .detail-label {
- font-size: 26rpx;
- color: #666666;
- margin-right: 8rpx;
- }
- .detail-value {
- font-size: 26rpx;
- color: #ff0000;
- }
- .purchase-row {
- justify-content: flex-end;
- }
- .purchase-input-wrap {
- flex-direction: row;
- align-items: center;
- background-color: #f5f5f5;
- border-radius: 8rpx;
- padding: 8rpx 12rpx;
- }
- .purchase-input {
- width: 120rpx;
- height: 48rpx;
- font-size: 26rpx;
- color: #ff0000;
- text-align: right;
- background: transparent;
- }
- .purchase-unit {
- font-size: 24rpx;
- color: #666666;
- margin-left: 8rpx;
- }
- .empty-tip {
- align-items: center;
- padding: 100rpx 20rpx;
- }
- .empty-tip-text {
- color: #999999;
- font-size: 28rpx;
- }
- .bottom-space {
- height: 40rpx;
- }
- .bottom-buttons {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- padding: 20rpx 30rpx;
- background-color: #ffffff;
- border-top: 1rpx solid #e5e5e5;
- }
- .submit-btn {
- width: 100%;
- height: 88rpx;
- background-color: #007aff;
- color: #ffffff;
- font-size: 32rpx;
- font-weight: 600;
- border-radius: 22rpx;
- border: none;
- }
- </style>
|