index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <template>
  2. <z-paging ref="paging" bgColor="#F7F7F7" safe-area-inset-bottom paging-class="paging-btm-shadow" scroll-with-animation>
  3. <template #top>
  4. <ut-navbar :title="did ? '编辑库房' : '新增库房'" :fixed="false" border ></ut-navbar>
  5. </template>
  6. <up-form class="p-rtv" labelPosition="top" :model="form" :rules="rules" labelWidth="auto" ref="upFormRef">
  7. <view class="pd-24">
  8. <view class="startline-title">库房信息</view>
  9. </view>
  10. <view class="pd-24 bg-#fff mb-10">
  11. <view class="h-1" id="typepppp"></view>
  12. <ut-action-sheet v-model="form.type" :tabs="pt_warehouse_type" title="选择库房类型">
  13. <up-form-item borderBottom label="库房类型" required prop="type">
  14. <view v-if="form.type" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_warehouse_type, form.type) }}</view>
  15. <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择库房类型</view>
  16. <template #right>
  17. <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
  18. </template>
  19. </up-form-item>
  20. </ut-action-sheet>
  21. <view class="h-1" id="warehouseNamepppp"></view>
  22. <up-form-item borderBottom label="库房名称" required prop="warehouseName">
  23. <up-input v-model="form.warehouseName" placeholder="请输入库房名称" border="none" clearable></up-input>
  24. </up-form-item>
  25. <up-form-item borderBottom label="库房编号" prop="sn">
  26. <up-input v-model="form.sn" placeholder="请输入库房编号" border="none" clearable></up-input>
  27. </up-form-item>
  28. <up-form-item borderBottom label="库房面积" prop="area">
  29. <up-input v-model="form.area" type="number" placeholder="请输入库房面积" border="none" clearable></up-input>
  30. <template #right>
  31. <span>平方米</span>
  32. </template>
  33. </up-form-item>
  34. <up-form-item borderBottom label="所在位置" prop="address">
  35. <up-input v-model="form.address" placeholder="请输入所在位置" border="none" clearable></up-input>
  36. </up-form-item>
  37. <view class="h-1" id="contactpppp"></view>
  38. <up-form-item @click="selectStorageMember" borderBottom label="负责人" required prop="contact">
  39. <view v-if="form.contact" class="f-s-30 c-333 f-w-5 flex1">{{ form.contactName }}</view>
  40. <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择负责人</view>
  41. <template #right>
  42. <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
  43. </template>
  44. </up-form-item>
  45. <!-- 填写基地联系电话 -->
  46. <view class="h-1" id="telpppp"></view>
  47. <up-form-item borderBottom label="联系电话" required prop="tel">
  48. <up-input v-model="form.tel" placeholder="请输入联系电话" border="none" clearable></up-input>
  49. </up-form-item>
  50. <up-form-item label="库房条件" prop="storageCondition">
  51. <up-textarea v-model="form.storageCondition" placeholder="请输入库房条件" maxlength="300" autoHeight clearable></up-textarea>
  52. </up-form-item>
  53. <up-form-item label="备注" prop="remark">
  54. <up-textarea v-model="form.remark" placeholder="请输入备注" maxlength="300" autoHeight clearable></up-textarea>
  55. </up-form-item>
  56. </view>
  57. <view class="pd-24">
  58. <view class="startline-title">货位信息</view>
  59. </view>
  60. <view class="pd-24 bg-#fff mb-10">
  61. <up-form-item borderBottom :label="`货位数量(${form?.shelves?.length || 0})`" prop="shelves"> </up-form-item>
  62. <up-swipe-action>
  63. <template v-for="(item, index) in form.shelves" :key="index">
  64. <up-swipe-action-item class="mb-20" :options="shelveOptions" @click="clickShelveSwipe($event, item, index)">
  65. <view class="plot-item pd-24">
  66. <view class="f-s-32 f-w-5 c-#333">{{ item?.shelvesName || '-' }}</view>
  67. <view v-if="item?.sn" class="f-s-24 c-#666">{{ item?.sn }}</view>
  68. <view class="pd-5"></view>
  69. <view class="f-s-28 c-#333" v-if="item?.remark">
  70. <span class="">备注:</span>
  71. <span class="c-#333 f-w-5">{{ item?.remark }}</span>
  72. </view>
  73. </view>
  74. </up-swipe-action-item>
  75. </template>
  76. </up-swipe-action>
  77. <up-button @click="addShelve()" type="primary" text="确定" plain>
  78. <up-icon class="mr-10" name="plus" color="#37A954"></up-icon>
  79. <span>添加货位信息</span>
  80. </up-button>
  81. </view>
  82. </up-form>
  83. <template #bottom>
  84. <view class="base-bottom-wrap pd-20 pb-0">
  85. <up-button type="primary" @click="submit">
  86. <text>{{ did ? '保存' : '提交' }}</text>
  87. </up-button>
  88. </view>
  89. </template>
  90. </z-paging>
  91. <!-- 悬浮新增按钮(编辑页通常不需要,但与列表风格一致时可保留) -->
  92. <!-- <ut-suspension @click="submit">
  93. <image src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/addBase.png" mode="widthFix" class="w-120 h-120"></image>
  94. </ut-suspension> -->
  95. <!-- 货位表单弹窗:新增/编辑 -->
  96. <FormShelve v-if="showShelve" v-model:show="showShelve" v-model="rowShelve" :title="shelveTitle" @submit="submitFormShelveAdd" />
  97. <FormShelve v-if="showShelveEdit" v-model:show="showShelveEdit" v-model="rowShelveEdit" :title="shelveTitle" @submit="submitFormShelveEdit" />
  98. </template>
  99. <script setup lang="ts">
  100. import { WarehouseAddDTO, WarehouseShelfAddDTO } from './index';
  101. import { useClientRequest } from '@/utils/request';
  102. import FormShelve from './models/form-shelve.vue';
  103. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  104. const { pt_warehouse_type } = toRefs<any>(proxy?.useDict('pt_warehouse_type'));
  105. const upFormRef = ref();
  106. const paging = ref();
  107. const did = ref<string>('');
  108. const form = ref<WarehouseAddDTO>({
  109. warehouseName: '',
  110. sn: '',
  111. type: '',
  112. contactName: '',
  113. tel: '',
  114. address: '',
  115. area: undefined,
  116. storageCondition: '',
  117. extraInfo: '',
  118. remark: '',
  119. shelves: [],
  120. });
  121. const rules = {
  122. warehouseName: [{ required: true, message: '请输入库房名称', trigger: ['blur', 'change'] }],
  123. type: [{ required: true, message: '请选择库房类型', trigger: ['change'] }],
  124. tel: [
  125. {
  126. validator: (rule: any, value: string) => {
  127. if (!value) return true;
  128. return /^\d[\d-]{5,20}$/.test(value);
  129. },
  130. message: '联系电话格式不正确',
  131. trigger: ['blur', 'change'],
  132. },
  133. ],
  134. area: [
  135. {
  136. validator: (rule: any, value: any) => {
  137. if (value === undefined || value === null || value === '') return true;
  138. return Number(value) >= 0;
  139. },
  140. message: '面积需为非负数',
  141. trigger: ['blur', 'change'],
  142. },
  143. ],
  144. };
  145. const loadDetail = async (id: string) => {
  146. if (!id) return;
  147. const res = await useClientRequest.get(`/plt-api/app/warehouse/getInfoById/${id}`);
  148. if (res && res.code === 200) {
  149. const data = res.data || {};
  150. // 仅映射已知字段,避免污染
  151. form.value = {
  152. warehouseName: data.warehouseName || '',
  153. sn: data.sn || '',
  154. type: data.type || '',
  155. contact: data.contact || '',
  156. contactName: data.contactName || '',
  157. tel: data.tel || '',
  158. address: data.address || '',
  159. area: data.area || '',
  160. storageCondition: data.storageCondition || '',
  161. extraInfo: data.extraInfo || '',
  162. remark: data.remark || '',
  163. shelves: data.shelves || [],
  164. } as WarehouseAddDTO;
  165. }
  166. };
  167. const submit = async () => {
  168. try {
  169. await upFormRef.value?.validate();
  170. } catch (error: any) {
  171. // 滚动到第一个错误字段
  172. const firstErrorField = error && error[0].prop + 'pppp';
  173. paging.value?.scrollIntoViewById(firstErrorField, 30, true);
  174. return;
  175. }
  176. try {
  177. await uni.showLoading({ title: did.value ? '保存中...' : '提交中...', mask: true });
  178. const url = did.value ? '/plt-api/app/warehouse/update' : '/plt-api/app/warehouse/add';
  179. const payload = { ...(form.value as any) };
  180. if (did.value) payload.id = did.value;
  181. const res = await useClientRequest.post(url, payload);
  182. uni.hideLoading();
  183. if (res && res.code === 200) {
  184. uni.showToast({ title: did.value ? '保存成功' : '新增成功', icon: 'success' });
  185. uni.$emit('refreshStorageRoomList');
  186. uni.$emit('storage-room-detail-refresh');
  187. setTimeout(() => uni.navigateBack(), 300);
  188. }
  189. } catch (e) {
  190. uni.hideLoading();
  191. console.error('保存库房失败:', e);
  192. }
  193. };
  194. const selectStorageMember = () => {
  195. uni.$on('selectCpyMember', (item: any) => {
  196. form.value.contact = item.userInfo?.id;
  197. form.value.contactName = item.userInfo?.name;
  198. form.value.tel = item.userInfo?.phone;
  199. uni.$off('selectCpyMember');
  200. });
  201. uni.$u.route({
  202. type: 'navigateTo',
  203. url: '/tools/select-cpy-member/index',
  204. });
  205. };
  206. // 货位增删改
  207. const shelveOptions = ref([
  208. { text: '编辑', name: 'edit', style: { backgroundColor: '#37a954', color: '#fff' } },
  209. { text: '删除', name: 'delete', style: { backgroundColor: '#FF3B30', color: '#fff' } },
  210. ]);
  211. const showShelve = ref(false);
  212. const showShelveEdit = ref(false);
  213. const shelveTitle = ref('添加货位');
  214. const rowShelve = ref<WarehouseShelfAddDTO>({ shelvesName: '', sn: '', remark: '', warehouseId: 0 });
  215. const rowShelveEdit = ref<WarehouseShelfAddDTO>({ shelvesName: '', sn: '', remark: '', warehouseId: 0 });
  216. const rowShelveEditIdx = ref<number>(-1);
  217. const addShelve = () => {
  218. rowShelve.value = { shelvesName: '', sn: '', remark: '', warehouseId: did.value ? Number(did.value) : 0 };
  219. shelveTitle.value = '添加货位';
  220. showShelve.value = true;
  221. };
  222. const clickShelveSwipe = (e: any, item: WarehouseShelfAddDTO, idx: number) => {
  223. const index = e.index;
  224. if (index === 0) {
  225. // 编辑
  226. shelveTitle.value = '编辑货位';
  227. rowShelveEdit.value = { ...(item || {}) } as WarehouseShelfAddDTO;
  228. rowShelveEditIdx.value = idx;
  229. showShelveEdit.value = true;
  230. }
  231. if (index === 1) {
  232. // 删除
  233. form.value.shelves?.splice(idx, 1);
  234. }
  235. };
  236. const submitFormShelveAdd = (data: WarehouseShelfAddDTO) => {
  237. form.value.shelves?.push({ ...data });
  238. };
  239. const submitFormShelveEdit = (data: WarehouseShelfAddDTO) => {
  240. if (rowShelveEditIdx.value === -1) return;
  241. form.value.shelves![rowShelveEditIdx.value] = { ...data };
  242. };
  243. onLoad((options: any) => {
  244. did.value = options?.id || '';
  245. if (did.value) {
  246. loadDetail(did.value);
  247. }
  248. paging.value?.complete();
  249. });
  250. </script>
  251. <style lang="scss" scoped>
  252. .startline-title {
  253. font-size: 32rpx;
  254. font-weight: 600;
  255. color: #333;
  256. }
  257. .base-bottom-wrap {
  258. background-color: #fff;
  259. }
  260. .plot-item {
  261. border: 1rpx solid rgba($u-primary, 0.4);
  262. border-radius: 10rpx;
  263. }
  264. </style>