index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <template>
  2. <z-paging ref="paging" v-model="list" paging-class="paging-btm-shadow" bgColor="#f7f7f7" safe-area-inset-bottom @query="query">
  3. <template #top>
  4. <ut-navbar leftText="请选择任务所使用的种源信息" :fixed="false"></ut-navbar>
  5. </template>
  6. <view class="d-flex a-c pd-24 pb-0 bg-#f7f7f7">
  7. <view class="min-w-170 flex1">
  8. <ut-action-sheet v-model="form.instoreType" :tabs="[{ label: '全部', value: '' }, ...pt_seed_instore_type]" @change="changeSeach" title="选择原料类型">
  9. <view class="d-flex search-select-item a-c">
  10. <view class="flex1 ov-hd f-s-28 c-333 text-center f-w-5 w-s-no">{{ selectDictLabel(pt_seed_instore_type, form.instoreType) || '全部' }}</view>
  11. <up-icon size="24rpx" color="#333" name="arrow-down-fill" class="mr-5"></up-icon>
  12. </view>
  13. </ut-action-sheet>
  14. </view>
  15. <view class="h-86 pl-20 w-100%">
  16. <ut-search ref="searchRef" v-model="form.keyword" @search="changeSeach" @change="changeSeach" margin="0" :border="false" placeholder="搜批次号、品种名、基地名" bgColor="#fff" height="86rpx" borderRadius="10rpx"></ut-search>
  17. </view>
  18. </view>
  19. <template v-for="(item, index) in list" :key="index">
  20. <info-card :item="item" :selected="selectedItems.has(item.id)" @click="toggleSelection(item)" />
  21. </template>
  22. <template #bottom>
  23. <view v-if="formDate.inputs.length > 0" class="bg-#EBF6EE c-primary f-s-24 pd-10 pl-24">
  24. 已选择种源:
  25. <template v-for="(item, index) in formDate.inputs" :key="index">
  26. <text v-if="index !== 0">、</text>
  27. {{ item.variety }}
  28. </template>
  29. </view>
  30. <view class="pd-20 d-flex">
  31. <up-button type="primary" @click="open">确认选择</up-button>
  32. </view>
  33. </template>
  34. </z-paging>
  35. <up-popup v-if="show" :show="show" :round="10" mode="bottom" @close="close" @open="open" closeable>
  36. <scroll-view style="height: 80vh" scroll-y>
  37. <view class="d-flex a-c pd-24">
  38. <view class="f-s-34 f-w-5 c-#333">关联种源信息</view>
  39. <view class="bg-#37A954 radius-10 pd4-10-20-10-20 d-flex a-c" style="width: max-content">
  40. <up-icon name="plus" color="#fff" size="24rpx"></up-icon>
  41. <view class="c-#fff f-s-22">添加种源关联信息</view>
  42. </view>
  43. </view>
  44. <view class="pd-24">
  45. <up-form class="p-rtv" labelPosition="top" :model="formDate" :rules="rules" labelWidth="auto" ref="upFormRef">
  46. <up-form-item :borderBottom="false" required label="种源投入时间" prop="useDate" id="useDatepppp">
  47. <ut-datetime-picker v-model="formDate.useDate" mode="date" dateFields="day" style="width: 100%">
  48. <view class="d-flex">
  49. <up-input v-model="formDate.useDate" readonly placeholder="默认种养殖开始时间但可修改" border="bottom"></up-input>
  50. <up-icon size="22rpx" color="#37A954" name="arrow-down-fill" style="margin-left: -20rpx"></up-icon>
  51. </view>
  52. </ut-datetime-picker>
  53. </up-form-item>
  54. <up-form-item :borderBottom="false" prop="inputs" id="inputspppp">
  55. <view class="d-flex flex-cln" style="width: 100%">
  56. <template v-for="(item, index) in Array.from(selectedItems.values())" :key="index">
  57. <souceinfo showClose :data="item" :index="index" v-model:inputs="formDate.inputs[index]" @close="handleSourceClose" />
  58. </template>
  59. </view>
  60. </up-form-item>
  61. <up-form-item :borderBottom="false" label="备注/说明" prop="remark">
  62. <up-textarea v-model="formDate.remark" placeholder="请输入备注/说明" border="bottom"></up-textarea>
  63. </up-form-item>
  64. </up-form>
  65. </view>
  66. <view class="pd-20 d-flex">
  67. <up-button type="primary" @click="saveSeedInfo">确认添加</up-button>
  68. </view>
  69. </scroll-view>
  70. </up-popup>
  71. </template>
  72. <script setup lang="ts">
  73. import { useClientRequest } from '@/utils/request';
  74. import InfoCard from './models/info-card.vue';
  75. import Souceinfo from './models/souceinfo.vue';
  76. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  77. const { pt_seed_instore_type } = toRefs<any>(proxy?.useDict('pt_seed_instore_type'));
  78. interface SeedItem {
  79. id: number | string;
  80. [key: string]: any;
  81. }
  82. const list = ref<SeedItem[]>([]);
  83. const paging = ref();
  84. const form = ref({
  85. keyword: '',
  86. instoreType: '',
  87. });
  88. //表单
  89. const formDate = ref({
  90. useDate: '',
  91. inputs: [] as any,
  92. remark: '',
  93. });
  94. // 自定义inputs校验函数
  95. const validateInputs = (rule: any, value: any, callback: any) => {
  96. // value 应该是 inputs 数组
  97. if (!value || !Array.isArray(value) || value.length === 0) {
  98. callback(new Error('请至少添加一个种源并填写用量'));
  99. return;
  100. }
  101. // 检查每个物料
  102. for (const item of value) {
  103. if (!item || typeof item !== 'object') {
  104. callback(new Error('种源数据格式错误'));
  105. return;
  106. }
  107. const { seedId, amount } = item;
  108. console.log(item, 'item');
  109. if (!seedId) {
  110. callback(new Error('种源ID缺失'));
  111. return;
  112. }
  113. if (amount === undefined || amount === null || amount === '') {
  114. callback(new Error('请填写种源用量'));
  115. return;
  116. }
  117. const amounts = Number(amount);
  118. if (isNaN(amounts) || amounts <= 0) {
  119. callback(new Error('种源用量必须大于0'));
  120. return;
  121. }
  122. }
  123. callback();
  124. };
  125. // 表单验证规则
  126. const rules = ref({
  127. useDate: [{ required: true, message: '请选择种源投入时间' }],
  128. inputs: [{ validator: validateInputs, trigger: 'blur' }],
  129. remark: [{ required: false, message: '请填写备注/说明' }],
  130. });
  131. const selectedItems = ref(new Map<string | number, SeedItem>());
  132. const query = async (pageNo: number, pageSize: number) => {
  133. const params = {
  134. pageNo,
  135. pageSize,
  136. ...form.value,
  137. };
  138. const res = await useClientRequest.get('/plt-api/app/storageSeed/page', params);
  139. const { rows } = res;
  140. paging.value.complete(rows);
  141. };
  142. const changeSeach = () => {
  143. paging.value.reload();
  144. };
  145. const toggleSelection = (item: SeedItem) => {
  146. const newMap = new Map(selectedItems.value);
  147. if (newMap.has(item.id)) {
  148. // 取消选择
  149. newMap.delete(item.id);
  150. formDate.value.inputs = formDate.value.inputs.filter((inputItem: any) => inputItem.seedId !== item.id);
  151. } else {
  152. // 防止重复添加
  153. if (!formDate.value.inputs.some((inputItem: any) => inputItem.seedId === item.id)) {
  154. formDate.value.inputs.push({
  155. taskId: taskId.value,
  156. seedId: item.id,
  157. amount: '',
  158. variety: item?.variety,
  159. });
  160. }
  161. newMap.set(item.id, item);
  162. }
  163. selectedItems.value = newMap;
  164. console.log('当前选中的种子:', Array.from(newMap.keys()));
  165. console.log('表单数据:', formDate.value.inputs);
  166. };
  167. // 创建响应式数据
  168. const show = ref(false);
  169. // 定义方法
  170. const open = () => {
  171. // 打开逻辑,比如设置 show 为 true
  172. show.value = true;
  173. // 获取所有选中的完整对象
  174. const selectedArray = Array.from(selectedItems.value.values());
  175. console.log('选中的完整项目:', selectedArray);
  176. // 这里可以使用 selectedArray 进行后续处理
  177. };
  178. const close = () => {
  179. // 关闭逻辑,设置 show 为 false
  180. show.value = false;
  181. // console.log('close');
  182. };
  183. // 处理种源信息关闭事件
  184. const handleSourceClose = (index: number) => {
  185. // 根据索引找到对应的项目
  186. const selectedArray = Array.from(selectedItems.value.values());
  187. if (index >= 0 && index < selectedArray.length) {
  188. const item = selectedArray[index];
  189. console.log(item, 'item');
  190. const newMap = new Map(selectedItems.value);
  191. // 从 selectedItems 中删除对应的项目
  192. newMap.delete(item.id);
  193. selectedItems.value = newMap;
  194. // 从 formDate.inputs 中删除对应的数据
  195. // 注意:由于删除后数组索引会变化,我们需要根据 seedId 来过滤
  196. formDate.value.inputs = formDate.value.inputs.filter((input: any) => input.seedId !== item.id);
  197. }
  198. };
  199. const upFormRef = ref();
  200. //校验表单然后提交
  201. const saveSeedInfo = async () => {
  202. uni.$u.debounce(
  203. async () => {
  204. try {
  205. console.log('开始校验');
  206. console.log(formDate.value, 'formDate.value');
  207. await upFormRef.value?.validate();
  208. console.log('校验完成');
  209. formDate.value.inputs.forEach((item: any) => {
  210. // 正确赋值方式
  211. item.taskId = taskId.value;
  212. item.remark = formDate.value.remark;
  213. item.useDate = formDate.value.useDate;
  214. });
  215. console.log(formDate.value.inputs);
  216. const params = [...formDate.value.inputs];
  217. console.log('提交参数:', params);
  218. // 这里需要根据实际 API 进行调整
  219. const res = await useClientRequest.post('/plt-api/app/seedInfo/saveSeedInfoBatch', params);
  220. if (res.code == 200) {
  221. uni.showToast({
  222. title: '提交成功',
  223. icon: 'success',
  224. duration: 2000,
  225. });
  226. setTimeout(() => {
  227. //发送emit
  228. uni.$emit('updatesuperviselist');
  229. uni.navigateBack({
  230. delta: 1,
  231. });
  232. }, 1000);
  233. }
  234. } catch (error: any) {
  235. console.log('表单验证错误:', error);
  236. // 滚动到第一个错误字段
  237. if (error && error[0]?.field) {
  238. const firstErrorField = error[0].field + 'pppp';
  239. paging.value?.scrollIntoViewById(firstErrorField, 30, true);
  240. }
  241. return;
  242. }
  243. },
  244. 1000,
  245. true,
  246. );
  247. };
  248. const taskId = ref('');
  249. onLoad((options: any) => {
  250. taskId.value = options?.taskId;
  251. });
  252. //卸载监听
  253. onUnload(() => {
  254. uni.$off('updatesuperviselist');
  255. });
  256. </script>
  257. <style lang="scss" scoped>
  258. .search-select-item {
  259. height: 86rpx;
  260. background-color: #fff;
  261. border-radius: 10rpx;
  262. box-sizing: border-box;
  263. padding: 12rpx;
  264. }
  265. </style>