index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. <template>
  2. <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" @query="query" safe-area-inset-bottom>
  3. <template #top>
  4. <ut-navbar title="添加管理记录" :fixed="false"></ut-navbar>
  5. </template>
  6. <view class="pt-24">
  7. <up-form class="p-rtv" labelPosition="top" :model="form" :rules="rules" labelWidth="auto" ref="upFormRef">
  8. <view class="startline-title pl-24 ml-24 mb-16">管理记录信息</view>
  9. <view class="bg-#fff pd-24 mb-20">
  10. <!-- 操作日期 -->
  11. <view class="h-1" id="operationDatepppp"></view>
  12. <up-form-item :borderBottom="false" label="操作日期" required prop="operationDate">
  13. <ut-datetime-picker v-model="form.operationDate.activityStart" mode="date" dateFields="day" @change="changeStartTime">
  14. <view class="d-flex mr-20">
  15. <up-input v-model="form.operationDate.activityStart" placeholder="请选择操作开始时间" border="bottom" :customStyle="{ paddingLeft: '0rpx' }"></up-input>
  16. <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill" style="margin-left: -20rpx"></up-icon>
  17. </view>
  18. </ut-datetime-picker>
  19. <ut-datetime-picker v-model="form.operationDate.activityEnd" mode="date" dateFields="day">
  20. <view class="d-flex">
  21. <up-input v-model="form.operationDate.activityEnd" placeholder="请选择操作结束时间" border="bottom" :customStyle="{ paddingLeft: '0rpx' }"></up-input>
  22. <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill" style="margin-left: -20rpx"></up-icon>
  23. </view>
  24. </ut-datetime-picker>
  25. </up-form-item>
  26. <!-- 操作类型-组培架 -->
  27. <ut-action-sheet v-if="landType == '3'" v-model="form.opMethod" :tabs="pt_breed_op_method" title="选择操作类型" mode="custom">
  28. <up-form-item borderBottom label="操作类型" required prop="opMethod" id="opMethodpppp">
  29. <view v-if="form.opMethod" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_breed_op_method, form.opMethod) }}</view>
  30. <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择操作类型</view>
  31. <template #right>
  32. <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
  33. </template>
  34. </up-form-item>
  35. </ut-action-sheet>
  36. <!-- 操作类型-地块 -->
  37. <ut-action-sheet v-else v-model="form.opMethod" :tabs="pt_op_method" title="选择操作类型" mode="custom">
  38. <up-form-item borderBottom label="操作类型" required prop="opMethod" id="opMethodpppp">
  39. <view v-if="form.opMethod" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_op_method, form.opMethod) }}</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. </ut-action-sheet>
  46. <!-- 自填操作类型 -->
  47. <up-form-item v-if="form.opMethod == '99'" borderBottom label="自填操作类型" required prop="cusOp" id="cusOppppp">
  48. <up-input v-model="form.cusOp" placeholder="请输入自填操作类型" border="none"></up-input>
  49. </up-form-item>
  50. <!-- 操作对象 -->
  51. <up-form-item v-if="landType == '3'" borderBottom label="操作对象" required prop="targetType" id="targetTypeppppp">
  52. <up-radio-group v-model="form.targetType">
  53. <up-radio :customStyle="{ marginRight: '60rpx' }" v-for="(item, index) in pt_breed_op_object" :key="index" :label="item.label" :name="item.value"></up-radio>
  54. </up-radio-group>
  55. </up-form-item>
  56. <!-- 操作组地块 -->
  57. <up-form-item v-if="landType !== '3'" :borderBottom="false" label="操作组地块" required prop="landIds" id="baseIdpppp">
  58. <view v-if="!deawerData" class="w-100% d-flex a-c j-c pd-24 b-radius bg-#FBFDFB border-#AFDDBB" @click="goSelectBase(landType || '')">
  59. <view class=""></view>
  60. <view class="f-s-34 c-primary">请选择操作组地块</view>
  61. </view>
  62. <view class="w-100%" v-else>
  63. <Baseinfo :modeValue="deawerData" @close="handleBaseinfoClose" :baseType="'1'" />
  64. </view>
  65. </up-form-item>
  66. <!-- 操作组培架 -->
  67. <up-form-item v-if="form.targetType == '1' && landType == '3'" :borderBottom="false" label="操作组培架" required prop="landIds" id="landIdspppp">
  68. <view v-if="!deawerData" class="w-100% d-flex a-c j-c pd-24 b-radius bg-#FBFDFB border-#AFDDBB" @click="goSelectBase(landType)">
  69. <view class=""></view>
  70. <view class="f-s-34 c-primary">请选择操作组培架</view>
  71. </view>
  72. <view class="w-100%" v-else>
  73. <Baseinfo :modeValue="deawerData" @close="handleBaseinfoClose" :baseType="'1'" />
  74. </view>
  75. </up-form-item>
  76. <!-- 操作个体选择 -->
  77. <up-form-item v-if="form.targetType == '2' && landType == '3'" :borderBottom="false" label="操作个体选择" required prop="animalIds" id="animalIdspppp">
  78. <view class="flex1">
  79. <Individualinfo v-if="individualLandIds?.checkBox?.length > 0" v-model="individualLandIds" v-model:landIds="form.animalIds" />
  80. <view class="w-100% gap-20 d-flex a-c" id="selectanimalId">
  81. <view class="w-50% d-flex a-c j-c pd-24 b-radius bg-#FBFDFB border-#AFDDBB" @click="showDeleteDialog = true">
  82. <view class=""></view>
  83. <view class="f-s-34 c-primary">手动输入添加</view>
  84. </view>
  85. <view class="w-50% d-flex a-c j-c pd-24 b-radius bg-#FBFDFB border-#AFDDBB" @click="goIndividual()">
  86. <view class=""></view>
  87. <view class="f-s-34 c-primary">从任务中快速选择</view>
  88. </view>
  89. </view>
  90. </view>
  91. </up-form-item>
  92. <!-- 操作方式 -->
  93. <up-form-item borderBottom label="操作方式" prop="opRemark" id="opRemarkpppp">
  94. <up-input v-model="form.opRemark" placeholder="如:人工锄草、机械中耕、喷雾器叶面喷施等" border="none"></up-input>
  95. </up-form-item>
  96. <!-- 记录人 -->
  97. <up-form-item borderBottom label="记录人" required prop="mgName" id="mgNamepppp">
  98. <up-input v-model="form.mgName" placeholder="请输入记录人" border="none"></up-input>
  99. </up-form-item>
  100. <!-- 是否使用物料 -->
  101. <up-form-item borderBottom label="是否使用物料" required prop="inputFlag" id="inputFlagpppp">
  102. <view class="d-flex flex-cln">
  103. <view v-if="!isAdd" class="c-#F19F18 f-s-24">因物料修改涉及退库操作,不支持修改!物料信息如有错误,请删除此条管理记录,重新添加。</view>
  104. <up-radio-group v-model="form.inputFlag">
  105. <up-radio :disabled="!isAdd" :customStyle="{ marginRight: '60rpx' }" v-for="(item, index) in yes_no" :key="index" :label="item.label" :name="item.value"></up-radio>
  106. </up-radio-group>
  107. </view>
  108. </up-form-item>
  109. <!-- 使用物料 -->
  110. <up-form-item v-if="+form.inputFlag" borderBottom label="使用物料" required prop="inputs" id="inputspppp">
  111. <view class="d-flex flex-cln w-100%">
  112. <view class="w-100%">
  113. <Materialinfo :showClose="Boolean(isAdd)" v-model:datas="MaterialData" v-model:inputs="form.inputs" />
  114. </view>
  115. <view v-if="Boolean(isAdd)" class="d-flex a-c j-c pd-24 b-radius bg-#FBFDFB border-#AFDDBB" @click="goMaterial()">
  116. <view class=""></view>
  117. <view class="f-s-34 c-primary">请选择此次农事使用的物料</view>
  118. </view>
  119. </view>
  120. </up-form-item>
  121. <!-- 备注 -->
  122. <up-form-item borderBottom label="备注/说明" prop="remark" id="remarkpppp">
  123. <up-input v-model="form.remark" placeholder="如:“防治阔叶杂草”、“花期追肥”" border="none"></up-input>
  124. </up-form-item>
  125. <up-form-item label="过程图片" prop="imgs" borderBottom id="imgspppp">
  126. <ut-upload v-model="form.imgs" :max-count="9" accept="image"></ut-upload>
  127. </up-form-item>
  128. <up-form-item label="过程视频" prop="videos" borderBottom id="videospppp">
  129. <ut-upload v-model="form.videos" :max-count="9" accept="video"></ut-upload>
  130. </up-form-item>
  131. </view>
  132. </up-form>
  133. </view>
  134. <template #bottom>
  135. <view class="pd-24 d-flex j-c gap-20 base-bottom-wrap">
  136. <up-button v-if="+isAdd" type="primary" @click="save()">确认添加</up-button>
  137. <up-button v-else type="primary" @click="change()">确认修改</up-button>
  138. </view>
  139. </template>
  140. </z-paging>
  141. <ut-confirm-dialog v-model:show="showDeleteDialog" width="75vw" title="添加个体标识" :confirmText="'确认'" :cancelText="'取消'" @confirm="handleAddConfirm" @cancel="handleAddCancel">
  142. <view class="">
  143. <view class="c-#333 f-s-28">个体标识号</view>
  144. <view class="">
  145. <up-input placeholder="请输入个体标识号" v-model="animalId" border="bottom"></up-input>
  146. </view>
  147. </view>
  148. </ut-confirm-dialog>
  149. </template>
  150. <script setup lang="ts">
  151. import { ref, reactive, computed, getCurrentInstance, type ComponentInternalInstance } from 'vue';
  152. import { useClientRequest } from '@/utils/request';
  153. import { useInfoStore } from '@/store';
  154. import Baseinfo from '../models/baseinfo.vue';
  155. import Materialinfo from '../models/materialinfo.vue';
  156. import Individualinfo from '../models/individualinfo.vue';
  157. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  158. const { yes_no, pt_breed_op_method, pt_op_method, pt_breed_op_object } = toRefs<any>(proxy?.useDict('yes_no', 'pt_breed_op_method', 'pt_op_method', 'pt_breed_op_object'));
  159. const deawerData = ref();
  160. const infoStore = useInfoStore();
  161. // 表单数据
  162. const form = ref({
  163. taskId: '',
  164. //管理类型 1-农事管理 2-投料
  165. activityType: '1',
  166. operationDate: {
  167. activityStart: null as string | null,
  168. activityEnd: null as string | null,
  169. },
  170. //作用对象类型 1-地块 2-动物
  171. targetType: null as string | null,
  172. opMethod: null as string | null,
  173. cusOp: null as string | null,
  174. //操作地块
  175. landIds: [],
  176. animalIds: [] as any,
  177. opRemark: '',
  178. mgName: infoStore.userInfo?.name,
  179. //是否使用物料
  180. inputFlag: '0' as '0' | '1',
  181. //物料列表
  182. inputs: [] as any,
  183. remark: '',
  184. imgs: null as string | null,
  185. videos: null as string | null,
  186. landFlag: '0' as '0' | '1',
  187. });
  188. const baseId = ref('');
  189. const Material = ref();
  190. //判断是新增还是修改
  191. const isAdd = ref(true);
  192. //判断基地的类型
  193. const landType = ref<string>();
  194. //个体信息数组
  195. const individualLandIds = ref<any>({});
  196. //打开添加个体
  197. const showDeleteDialog = ref(false);
  198. const animalId = ref<any>([]);
  199. //个体名称
  200. const variety = ref<any>();
  201. const handleAddCancel = () => {
  202. showDeleteDialog.value = false;
  203. animalId.value = '';
  204. };
  205. const handleAddConfirm = () => {
  206. individualLandIds.value.checkBox.push(animalId.value);
  207. animalId.value = '';
  208. showDeleteDialog.value = false;
  209. form.value.animalIds = individualLandIds.value.checkBox;
  210. };
  211. // 自定义校验函数:操作日期校验
  212. const validateOperationDate = (rule: any, value: any, callback: any) => {
  213. if (!value) {
  214. callback(new Error('请选择操作日期'));
  215. return;
  216. }
  217. const { activityStart, activityEnd } = value;
  218. if (!activityStart) {
  219. callback(new Error('请选择操作开始时间'));
  220. return;
  221. }
  222. if (!activityEnd) {
  223. callback(new Error('请选择操作结束时间'));
  224. return;
  225. }
  226. const start = new Date(activityStart);
  227. const end = new Date(activityEnd);
  228. if (end < start) {
  229. callback(new Error('操作结束时间必须晚于开始时间'));
  230. return;
  231. }
  232. callback();
  233. };
  234. //
  235. const changeStartTime = () => {
  236. if (!form.value?.operationDate?.activityEnd) {
  237. form.value.operationDate.activityEnd = form.value.operationDate.activityStart;
  238. }
  239. };
  240. // 自定义校验函数:自填操作类型校验(当opMethod为99时必填)
  241. const validateCusOp = (rule: any, value: any, callback: any) => {
  242. if (form.value.opMethod === '99' && !value) {
  243. callback(new Error('请输入自填操作类型'));
  244. return;
  245. }
  246. callback();
  247. };
  248. // 自定义inputs校验函数
  249. const validateInputs = (rule: any, value: any, callback: any) => {
  250. // value 应该是 inputs 数组
  251. if (!value || !Array.isArray(value) || value.length === 0) {
  252. callback(new Error('请至少添加一个物料并填写用量'));
  253. return;
  254. }
  255. // 检查每个物料
  256. for (const item of value) {
  257. if (!item || typeof item !== 'object') {
  258. callback(new Error('物料数据格式错误'));
  259. return;
  260. }
  261. const { id, inputAmount } = item;
  262. if (!id) {
  263. callback(new Error('物料ID缺失'));
  264. return;
  265. }
  266. if (inputAmount === undefined || inputAmount === null || inputAmount === '') {
  267. callback(new Error('请填写物料用量'));
  268. return;
  269. }
  270. const amount = Number(inputAmount);
  271. if (isNaN(amount) || amount <= 0) {
  272. callback(new Error('物料用量必须大于0'));
  273. return;
  274. }
  275. }
  276. callback();
  277. };
  278. // 表单验证规则
  279. const rules = reactive({
  280. operationDate: [{ validator: validateOperationDate, trigger: 'blur' }],
  281. opMethod: [{ required: true, message: '请选择操作类型' }],
  282. cusOp: [{ validator: validateCusOp, trigger: 'blur' }],
  283. opRemark: [{ required: false, message: '请输入操作方式' }],
  284. mgName: [{ required: true, message: '请输入记录人' }],
  285. inputFlag: [{ required: true, message: '请选择是否使用物料' }],
  286. remark: [{ required: false, message: '请输入备注' }],
  287. inputs: [{ validator: validateInputs, trigger: 'blur' }],
  288. });
  289. const paging = ref();
  290. const list = ref();
  291. const upFormRef = ref<any>();
  292. const query = async (pageNo: number, pageSize: number) => {
  293. const res = await useClientRequest.get('/plt-api/app/plantationTask/list', {
  294. pageNo,
  295. pageSize,
  296. });
  297. // return res.data;
  298. };
  299. const handleBaseinfoClose = () => {
  300. deawerData.value = null;
  301. };
  302. // 提交表单
  303. const save = () => {
  304. uni.$u.debounce(
  305. async () => {
  306. try {
  307. console.log('开始提交管理记录');
  308. await upFormRef.value?.validate();
  309. console.log('校验完成');
  310. const params = {
  311. ...form.value,
  312. ...form.value.operationDate,
  313. landFlag: deawerData?.value?.aloneChecked ? '1' : '0',
  314. };
  315. console.log('提交参数:', params);
  316. // 这里需要根据实际 API 进行调整
  317. const res = await useClientRequest.post('/plt-api/app/plantationActivity/saveActivity', params);
  318. if (res.code == 200) {
  319. uni.showToast({
  320. title: '提交成功',
  321. icon: 'success',
  322. duration: 2000,
  323. });
  324. setTimeout(() => {
  325. //发送emit
  326. uni.$emit('updatesuperviselist');
  327. uni.navigateBack({
  328. delta: 1,
  329. });
  330. }, 1000);
  331. }
  332. } catch (error: any) {
  333. console.log('表单验证错误:', error);
  334. // 滚动到第一个错误字段
  335. if (error && error[0]?.field) {
  336. const firstErrorField = error[0].field + 'pppp';
  337. paging.value?.scrollIntoViewById(firstErrorField, 30, true);
  338. }
  339. return;
  340. }
  341. },
  342. 1000,
  343. true,
  344. );
  345. };
  346. //修改提交表单
  347. const change = () => {
  348. uni.$u.debounce(
  349. async () => {
  350. try {
  351. console.log('开始提交管理记录');
  352. await upFormRef.value?.validate();
  353. console.log('校验完成');
  354. const params = {
  355. ...form.value,
  356. ...form.value.operationDate,
  357. landFlag: deawerData?.value?.aloneChecked ? '1' : '0',
  358. };
  359. console.log('提交参数:', params);
  360. // 这里需要根据实际 API 进行调整
  361. const res = await useClientRequest.post('/plt-api/app/plantationActivity/updateActivity', params);
  362. if (res.code == 200) {
  363. uni.showToast({
  364. title: '提交成功',
  365. icon: 'success',
  366. duration: 2000,
  367. });
  368. setTimeout(() => {
  369. //发送emit
  370. uni.$emit('updatesuperviselist');
  371. uni.navigateBack({
  372. delta: 1,
  373. });
  374. }, 1000);
  375. }
  376. } catch (error: any) {
  377. console.log('表单验证错误:', error);
  378. // 滚动到第一个错误字段
  379. if (error && error[0]?.field) {
  380. const firstErrorField = error[0].field + 'pppp';
  381. paging.value?.scrollIntoViewById(firstErrorField, 30, true);
  382. }
  383. return;
  384. }
  385. },
  386. 1000,
  387. true,
  388. );
  389. };
  390. //去操作地块页面选择地块
  391. const goSelectBase = (landType: string) => {
  392. uni.$once('updatelands', function (data) {
  393. deawerData.value = data;
  394. form.value.landIds = deawerData.value.checkBox;
  395. });
  396. uni.$u.route({ type: 'navigateTo', url: '/tools/supervise-plot/index', params: { baseId: baseId.value, landType } });
  397. };
  398. //去选择个体
  399. const goIndividual = () => {
  400. uni.$once('updateIndividual', function (data) {
  401. let flag = false;
  402. data?.checkBox.forEach((item: any) => {
  403. //判断有没有重复的值,如果有这个就不添加,没有就添加
  404. if (individualLandIds.value.checkBox.some((item2: any) => item2 === item)) {
  405. flag = true;
  406. } else {
  407. individualLandIds.value.checkBox.push(item);
  408. form.value.animalIds.push(item);
  409. }
  410. });
  411. if (flag) {
  412. uni.showToast({
  413. title: '有重复的个体,已经帮您过滤的',
  414. icon: 'none',
  415. });
  416. }
  417. paging.value?.scrollIntoViewById('selectanimalId', 30, true);
  418. });
  419. uni.$u.route({ type: 'navigateTo', url: '/tools/supervise-individual/index', params: { baseId: baseId.value, landType, taskId: form.value.taskId } });
  420. };
  421. const MaterialData = ref([]);
  422. //去选择物料
  423. const goMaterial = () => {
  424. if (!+isAdd.value) {
  425. return;
  426. }
  427. uni.$once('updateMaterial', function (data) {
  428. MaterialData.value = data?.data;
  429. data?.data.forEach((i) => {
  430. //判断 MaterialData.value中的id是否有i.id
  431. if (!MaterialData.value.find((item) => item.id === i.id)) {
  432. MaterialData.value.push(i);
  433. }
  434. });
  435. });
  436. uni.$u.route({ type: 'navigateTo', url: '/tools/supervise-material/index', params: { baseId: baseId.value } });
  437. };
  438. onLoad(async (options: any) => {
  439. baseId.value = options?.baseId;
  440. form.value.taskId = options?.taskId;
  441. isAdd.value = Boolean(+options?.add);
  442. landType.value = options?.landType;
  443. variety.value = options?.variety;
  444. console.log(Boolean(isAdd.value), 'isAdd.value', isAdd.value);
  445. individualLandIds.value = {
  446. checkBox: [],
  447. variety: variety.value,
  448. };
  449. if (landType.value == '3') {
  450. form.value.targetType = '1';
  451. }
  452. if (!+isAdd.value) {
  453. const res = await useClientRequest.get(`/plt-api/app/plantationActivity/getInfo/${options.id}`);
  454. if (!res || res.code !== 200) return;
  455. form.value = res.data;
  456. form.value.operationDate = {
  457. activityStart: res.data.activityStart,
  458. activityEnd: res.data.activityEnd,
  459. };
  460. deawerData.value = {
  461. ...res.data.baseInfo,
  462. area: res?.data?.baseInfo?.gapInfo?.area,
  463. areaUnit: res?.data?.baseInfo?.gapInfo?.areaUnit,
  464. adcodeName: res?.data?.baseInfo?.gapInfo?.adcodeName,
  465. medicineName: res?.data?.baseInfo?.gapInfo?.medicineName,
  466. aloneChecked: res?.data?.inputFlag == '1' ? true : false,
  467. data: res.data.lands,
  468. checkBox: res.data.landIds,
  469. };
  470. individualLandIds.value = {
  471. checkBox: res.data.animalIds,
  472. variety: variety.value,
  473. };
  474. MaterialData.value = res.data.inputMaterialList;
  475. res.data.inputMaterialList.forEach((i) => {
  476. if (!form.value.inputs) {
  477. form.value.inputs = [];
  478. }
  479. form.value.inputs.push({
  480. id: i.id,
  481. inputAmount: +i.quantity,
  482. });
  483. });
  484. }
  485. });
  486. </script>