WareHouseSupplierPicker.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <view>
  3. <view class="selector-mask" :class="{ show: visible }" @tap="close"></view>
  4. <view class="selector-panel" :class="{ show: visible }">
  5. <view class="selector-header">
  6. <view class="selector-action" @tap="close">取消</view>
  7. <view class="selector-title">选择供应商</view>
  8. <view class="selector-action" @tap="clear">清空</view>
  9. </view>
  10. <view class="selector-search">
  11. <u-search :show-action="false" v-model="keyword" placeholder="搜索供应商名称"></u-search>
  12. </view>
  13. <scroll-view scroll-y class="selector-list">
  14. <view v-if="loading" class="selector-state">加载中...</view>
  15. <view v-else-if="filteredList.length === 0" class="selector-state">暂无可选供应商</view>
  16. <view v-else class="selector-list-inner">
  17. <view class="selector-card" v-for="item in filteredList" :key="item.id" @tap="select(item)">
  18. <view class="selector-name">{{ item.name }}</view>
  19. <view class="selector-meta">
  20. <text v-if="item.address">地址:{{ item.address }}</text>
  21. <text v-if="item.telPhone">联系电话:{{ item.telPhone }}</text>
  22. </view>
  23. </view>
  24. </view>
  25. </scroll-view>
  26. </view>
  27. </view>
  28. </template>
  29. <script>
  30. import SupplierService from '@/api/psi/SupplierService'
  31. export default {
  32. name: 'WareHouseSupplierPicker',
  33. data() {
  34. return {
  35. visible: false,
  36. loading: false,
  37. keyword: '',
  38. supplierList: []
  39. }
  40. },
  41. supplierService: null,
  42. computed: {
  43. filteredList() {
  44. const keyword = (this.keyword || '').trim().toLowerCase()
  45. if (!keyword) {
  46. return this.supplierList
  47. }
  48. return this.supplierList.filter(item => (item.name || '').toLowerCase().includes(keyword))
  49. }
  50. },
  51. created() {
  52. this.supplierService = new SupplierService()
  53. },
  54. methods: {
  55. async open() {
  56. this.visible = true
  57. this.keyword = ''
  58. if (!this.supplierList.length) {
  59. await this.loadSuppliers()
  60. }
  61. },
  62. close() {
  63. this.visible = false
  64. },
  65. async loadSuppliers() {
  66. this.loading = true
  67. try {
  68. const data = await this.supplierService.list({
  69. current: 1,
  70. size: -1
  71. })
  72. this.supplierList = (data && data.records) || []
  73. } finally {
  74. this.loading = false
  75. }
  76. },
  77. select(item) {
  78. this.$emit('selected', item)
  79. this.close()
  80. },
  81. clear() {
  82. this.$emit('clear')
  83. this.close()
  84. }
  85. }
  86. }
  87. </script>
  88. <style scoped>
  89. .selector-mask {
  90. position: fixed;
  91. inset: 0;
  92. background: rgba(0, 0, 0, 0.35);
  93. opacity: 0;
  94. visibility: hidden;
  95. transition: all 0.25s ease;
  96. z-index: 1000;
  97. }
  98. .selector-mask.show {
  99. opacity: 1;
  100. visibility: visible;
  101. }
  102. .selector-panel {
  103. position: fixed;
  104. left: 0;
  105. right: 0;
  106. bottom: 0;
  107. height: 68vh;
  108. background: #f7f9fc;
  109. border-radius: 28rpx 28rpx 0 0;
  110. transform: translateY(100%);
  111. transition: transform 0.25s ease;
  112. z-index: 1001;
  113. display: flex;
  114. flex-direction: column;
  115. }
  116. .selector-panel.show {
  117. transform: translateY(0);
  118. }
  119. .selector-header {
  120. display: flex;
  121. align-items: center;
  122. justify-content: space-between;
  123. padding: 28rpx 32rpx 16rpx;
  124. background: #fff;
  125. border-bottom: 1rpx solid #eef2f7;
  126. }
  127. .selector-title {
  128. font-size: 32rpx;
  129. font-weight: 600;
  130. color: #1f2937;
  131. }
  132. .selector-action {
  133. min-width: 80rpx;
  134. font-size: 28rpx;
  135. color: #2979ff;
  136. }
  137. .selector-search {
  138. padding: 20rpx 24rpx 8rpx;
  139. background: #fff;
  140. }
  141. .selector-list {
  142. flex: 1;
  143. padding: 16rpx 24rpx 32rpx;
  144. }
  145. .selector-list-inner {
  146. display: flex;
  147. flex-direction: column;
  148. gap: 16rpx;
  149. }
  150. .selector-state {
  151. padding-top: 120rpx;
  152. text-align: center;
  153. font-size: 28rpx;
  154. color: #94a3b8;
  155. }
  156. .selector-card {
  157. background: #fff;
  158. border-radius: 20rpx;
  159. padding: 24rpx;
  160. box-shadow: 0 8rpx 24rpx rgba(15, 23, 42, 0.06);
  161. }
  162. .selector-name {
  163. font-size: 30rpx;
  164. font-weight: 600;
  165. color: #0f172a;
  166. }
  167. .selector-meta {
  168. display: flex;
  169. flex-direction: column;
  170. gap: 8rpx;
  171. margin-top: 12rpx;
  172. font-size: 24rpx;
  173. color: #64748b;
  174. }
  175. </style>