| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- <template>
- <view>
- <u-form-item label="商品名称" :prop="'detailInfos[' + index_experience + '].tradeName'" :required="true">
- <u--input :value="currentValue" placeholder="请选择商品名称" readonly :disabled="disabled"
- @focus="openPicker"></u--input>
- </u-form-item>
- <view class="selector-mask" :class="{ show: visible }" @tap="closePicker"></view>
- <view class="selector-panel" :class="{ show: visible }">
- <view class="selector-header">
- <view class="selector-action" @tap="closePicker">取消</view>
- <view class="selector-title">选择商品</view>
- <view class="selector-action selector-action-placeholder">取消</view>
- </view>
- <view class="selector-search">
- <u-search :show-action="false" v-model="keyword" placeholder="搜索商品名称"></u-search>
- </view>
- <scroll-view scroll-y class="selector-list">
- <view v-if="loading" class="selector-state">加载中...</view>
- <view v-else-if="filteredList.length === 0" class="selector-state">暂无可选商品</view>
- <view v-else class="selector-list-inner">
- <view class="goods-card" v-for="item in filteredList" :key="item.id || item.tradeName"
- @tap="selectItem(item)">
- <view class="goods-name">{{ item.tradeName }}</view>
- <view class="goods-meta" v-if="item.company || item.spec">
- <text v-if="item.company">单位:{{ item.company }}</text>
- <text v-if="item.spec">规格:{{ item.spec }}</text>
- </view>
- </view>
- </view>
- </scroll-view>
- </view>
- </view>
- </template>
- <script>
- import MaterialManagementService from '@/api/psi/MaterialManagementService'
- import WareHouseService from '@/api/psi/WareHouseService'
- export default {
- name: 'GoodsSelector',
- props: {
- index_experience: Number,
- inputForm: Object,
- disabled: Boolean
- },
- data() {
- return {
- visible: false,
- loading: false,
- keyword: '',
- goodsList: [],
- materialManagementService: null,
- wareHouseService: null
- }
- },
- computed: {
- currentRow() {
- return (this.inputForm.detailInfos || [])[this.index_experience] || {}
- },
- currentValue() {
- return this.currentRow.tradeName || ''
- },
- filteredList() {
- const keyword = (this.keyword || '').trim().toLowerCase()
- if (!keyword) {
- return this.goodsList
- }
- return this.goodsList.filter(item => (item.tradeName || '').toLowerCase().includes(keyword))
- }
- },
- created() {
- this.materialManagementService = new MaterialManagementService()
- this.wareHouseService = new WareHouseService()
- },
- methods: {
- isEmpty(value) {
- let result = false
- if (value == null || value == undefined) {
- result = true
- }
- if (typeof value === 'string' && (value.replace(/\s+/g, '') === '' || value === '')) {
- result = true
- }
- if (typeof value === 'object' && value instanceof Array && value.length === 0) {
- result = true
- }
- return result
- },
- async openPicker() {
- if (this.disabled) {
- return
- }
- if (this.isEmpty(this.currentRow.procurementTypeId)) {
- uni.showToast({
- title: '请先选择采购类型',
- icon: 'none'
- })
- return
- }
- this.visible = true
- this.keyword = ''
- await this.loadGoodsList()
- },
- closePicker() {
- this.visible = false
- },
- async loadGoodsList() {
- this.loading = true
- try {
- const data = await this.materialManagementService.findTradeByTypeId(this.currentRow.procurementTypeId)
- this.goodsList = (data || []).map(item => ({
- ...item,
- tradeName: item.tradeName || ''
- }))
- } catch (e) {
- this.goodsList = []
- uni.showToast({
- title: '商品数据加载失败',
- icon: 'none'
- })
- } finally {
- this.loading = false
- }
- },
- async selectItem(item) {
- let selected = { ...item }
- try {
- const data = await this.wareHouseService.wareHouseSummaryList({
- current: 1,
- size: 20,
- tradeName: item.tradeName,
- wareHouseType: this.currentRow.procurementTypeId,
- orders: []
- })
- const records = (data && data.records) || []
- if (records.length > 0) {
- selected = { ...records[0], ...selected }
- }
- } catch (e) {
- }
- this.$emit('selected', {
- index: this.index_experience,
- item: selected
- })
- this.closePicker()
- }
- }
- }
- </script>
- <style scoped>
- .selector-mask {
- position: fixed;
- inset: 0;
- background: rgba(0, 0, 0, 0.35);
- opacity: 0;
- visibility: hidden;
- transition: all 0.25s ease;
- z-index: 1000;
- }
- .selector-mask.show {
- opacity: 1;
- visibility: visible;
- }
- .selector-panel {
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
- height: 68vh;
- background: #f7f9fc;
- border-radius: 28rpx 28rpx 0 0;
- transform: translateY(100%);
- transition: transform 0.25s ease;
- z-index: 1001;
- display: flex;
- flex-direction: column;
- }
- .selector-panel.show {
- transform: translateY(0);
- }
- .selector-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 28rpx 32rpx 16rpx;
- background: #fff;
- border-bottom: 1rpx solid #eef2f7;
- }
- .selector-title {
- font-size: 32rpx;
- font-weight: 600;
- color: #1f2937;
- }
- .selector-action {
- min-width: 80rpx;
- font-size: 28rpx;
- color: #2979ff;
- }
- .selector-action-placeholder {
- opacity: 0;
- }
- .selector-search {
- padding: 20rpx 24rpx 8rpx;
- background: #fff;
- }
- .selector-list {
- flex: 1;
- padding: 16rpx 24rpx 32rpx;
- }
- .selector-list-inner {
- display: flex;
- flex-direction: column;
- gap: 16rpx;
- }
- .selector-state {
- padding-top: 120rpx;
- text-align: center;
- font-size: 28rpx;
- color: #94a3b8;
- }
- .goods-card {
- background: #fff;
- border-radius: 20rpx;
- padding: 24rpx;
- box-shadow: 0 8rpx 24rpx rgba(15, 23, 42, 0.06);
- }
- .goods-name {
- font-size: 30rpx;
- font-weight: 600;
- line-height: 1.45;
- color: #0f172a;
- }
- .goods-meta {
- display: flex;
- gap: 20rpx;
- margin-top: 10rpx;
- font-size: 24rpx;
- color: #64748b;
- flex-wrap: wrap;
- }
- </style>
|