prescriptionPage.vue 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. <template>
  2. <div class="prescription-page">
  3. <custom-header name="基本信息" isGoBack @goback="goBack"></custom-header>
  4. <div class="page-content">
  5. <div class="prescription-title">
  6. <!-- <img @click="goBack" src="@/assets/img/home/back.png" alt="" /> -->
  7. <div class="title-name">农场基本信息</div>
  8. <div class="title-desc">请认真核对一下内容</div>
  9. </div>
  10. <div class="prescription-box" v-loading="loadingPage">
  11. <!-- <div class="box-title">
  12. <img src="@/assets/img/home/label-icon.png" />
  13. 农场情况
  14. </div> -->
  15. <div class="box-content">
  16. <div class="box-item">
  17. <div class="item-name">
  18. <span>请选择您的果园土壤类型</span>
  19. </div>
  20. <div class="tips">土壤类型确认最佳施肥策略</div>
  21. <div class="item-checkbox">
  22. <el-radio-group v-model="basicForm.soilTypes">
  23. <el-radio-button v-for="(item, index) in basicFarmFormData.soilTypes" :key="index"
  24. :label="item.name" :value="item.code" />
  25. </el-radio-group>
  26. </div>
  27. </div>
  28. <div class="box-item">
  29. <div class="item-name">
  30. <span>请选择您的灌溉方式</span>
  31. <span class="sub-name"> (可多选)</span>
  32. </div>
  33. <div class="tips">灌溉方式确认药肥最佳配比</div>
  34. <div class="item-checkbox">
  35. <div class="tag-group add-tag-group">
  36. <div class="tag-item" :class="{ self: item.custom === true, selected: item.selected }"
  37. @click="handleSelect('irrigationMethods', idx, item.custom)"
  38. v-for="(item, idx) in basicFarmFormData.irrigationMethods" :key="'ce-' + idx">
  39. <span class="text">{{ item.name }}</span>
  40. </div>
  41. <div class="tag-item last-add" @click="handleAdd('irrigationMethods')"><el-icon
  42. class="add-icon">
  43. <Plus />
  44. </el-icon>其它方式</div>
  45. </div>
  46. </div>
  47. </div>
  48. <div class="box-item">
  49. <div class="item-name">
  50. <span>请选择您的农机设备</span>
  51. <span class="sub-name"> (可多选)</span>
  52. </div>
  53. <div class="tips">农闲时可将闲置农机加入农事服务联盟,获取额外服务收益</div>
  54. <div class="item-checkbox">
  55. <div class="tag-group add-tag-group">
  56. <div class="tag-item" :class="{ self: item.custom === true, selected: item.selected }"
  57. @click="handleMachinerySelect('machinery', idx, item)"
  58. v-for="(item, idx) in basicFarmFormData.machinery" :key="'nj-' + idx">
  59. <span class="text">{{ item.name }}</span>
  60. <span class="quantity-text" v-show="item.quantity">{{ item.quantity }}</span>
  61. </div>
  62. <div class="tag-item last-add" @click="handleMachineryAdd('machinery', item)"><el-icon
  63. class="add-icon">
  64. <Plus />
  65. </el-icon>其它设备</div>
  66. </div>
  67. </div>
  68. </div>
  69. <!-- 农场规模 -->
  70. <!-- <div class="farm-scale-header">
  71. <div class="farm-scale-title">请填写您的农场规模</div>
  72. <div class="farm-scale-desc">农闲时可以提供农事服务,获取额外收益</div>
  73. </div>
  74. <div class="farm-scale-form">
  75. <div class="farm-scale-item">
  76. <div class="farm-scale-label">
  77. 农场固定长工
  78. <div class="sub-label">(会操作各种小型农机)</div>
  79. </div>
  80. <el-input v-model="farmScale.regularWorkerCount" placeholder="请输入人数" class="farm-scale-input">
  81. <template #append>人</template>
  82. </el-input>
  83. </div>
  84. <div class="farm-scale-item">
  85. <label class="farm-scale-label">无人机植保人员</label>
  86. <el-input v-model="farmScale.plantProtectionWorkerCount" placeholder="请输入人数" class="farm-scale-input">
  87. <template #append>人</template>
  88. </el-input>
  89. </div>
  90. <div class="farm-scale-item">
  91. <label class="farm-scale-label">专业树形修剪人员</label>
  92. <el-input v-model="farmScale.pruningWorkerCount" placeholder="请输入人数" class="farm-scale-input">
  93. <template #append>人</template>
  94. </el-input>
  95. </div>
  96. <div class="farm-scale-item">
  97. <label class="farm-scale-label">专业嫁接换种人员</label>
  98. <el-input v-model="farmScale.graftingWorkerCount" placeholder="请输入人数" class="farm-scale-input">
  99. <template #append>人</template>
  100. </el-input>
  101. </div>
  102. <div class="farm-scale-item">
  103. <label class="farm-scale-label">农忙可调度人员</label>
  104. <el-input v-model="farmScale.tempDispatchWorkerCount" placeholder="请输入人数" class="farm-scale-input">
  105. <template #append>人</template>
  106. </el-input>
  107. </div>
  108. </div> -->
  109. <div class="box-item">
  110. <div class="item-name">
  111. <span>希望专家帮助解决的种植难题</span>
  112. <span class="sub-name"> (可多选)</span>
  113. </div>
  114. <div class="item-checkbox">
  115. <div class="tag-group add-tag-group">
  116. <div class="tag-item" :class="{ self: item.custom === true, selected: item.selected }"
  117. @click="handleSelect('improvementAreas', idx, item.custom)"
  118. v-for="(item, idx) in basicFarmFormData.improvementAreas" :key="'wt-' + idx">
  119. <span class="text">{{ item.name }}</span>
  120. </div>
  121. </div>
  122. </div>
  123. </div>
  124. <div class="box-item">
  125. <div class="item-name">
  126. <span>您最希望得到哪位荔枝专家的农事处方</span>
  127. </div>
  128. <div class="item-checkbox">
  129. <el-radio-group v-model="basicForm.expertCode">
  130. <el-radio-button v-for="(item, index) in basicFarmFormData.expertOptions" :key="index"
  131. :label="item.name" :value="item.code" />
  132. </el-radio-group>
  133. </div>
  134. </div>
  135. </div>
  136. </div>
  137. </div>
  138. <!-- 按钮 -->
  139. <div class="custom-bottom-fixed-btns">
  140. <!-- <div class="bottom-btn secondary-btn" @click="handlePage">跳过</div> -->
  141. <el-button class="bottom-btn primary-btn" :loading="loading" @click.stop="submit" @touchstart.stop @touchend.stop>确认信息</el-button>
  142. </div>
  143. </div>
  144. <popup class="add-tag-popup" round v-model:show="showAddPopup">
  145. <div class="tag-item" v-if="addTypeKey !== 'machinery' || (addTypeKey === 'machinery' && isMachineSelf)">
  146. <div class="popup-title">编辑<span class="name-text">{{ formNameObj[addTypeKey] }}</span><span
  147. class="ml-2">名称</span></div>
  148. <el-input class="popup-input" v-model="popupInputVal" :placeholder="'请输入' + formNameObj[addTypeKey]"
  149. size="large" />
  150. </div>
  151. <div class="device-item" v-if="addTypeKey === 'machinery'">
  152. <div class="popup-title">编辑
  153. <span class="name-text" v-show="isMachineSelf">{{ formNameObj[addTypeKey] }}</span>
  154. <span class="name-text" v-show="!isMachineSelf">{{ popupInputVal }}</span>
  155. <span class="ml-2">数量</span>
  156. </div>
  157. <el-input type="number" class="popup-input" v-model="popupInputNum"
  158. :placeholder="'请输入' + formNameObj[addTypeKey] + '数量'" size="large">
  159. <template #append>{{ machineryUnit || '辆' }}</template>
  160. </el-input>
  161. </div>
  162. <div class="popup-button">
  163. <div class="delete" v-if="isEditPopup && isMachineSelf" @click="handleDelete">删除</div>
  164. <div class="delete" v-else-if="isEditPopup && !isMachineSelf" @click="handleCancelSelect">取消选中</div>
  165. <div class="cancel" v-else @click="showAddPopup = false">取消</div>
  166. <div :class="{ disabled: isPopupConfirmDisabled() }" @click="handleConfirm">确认</div>
  167. </div>
  168. </popup>
  169. <!-- 物候期信息 -->
  170. <popup class="period-popup" round v-model:show="showPeriodPopup">
  171. <div class="period-header">为了{{ basicForm?.expertInfo?.name }}专家的处方体系适用于您的果园管理,请完善基本物候信息</div>
  172. <div class="period-content">
  173. <div class="period-item" v-for="(item, i) in phenologyList" :key="i">
  174. <div class="period-item-name">{{ item.typeName }}</div>
  175. <div class="period-item-label">
  176. <div class="label-item-group">
  177. <div class="label-item">当下物候期</div>
  178. <div class="label-item-value period-display">{{ item.phenologyName }}</div>
  179. </div>
  180. <div class="label-item-group">
  181. <div class="label-item">{{ item.startDateLabel || '起始时间' }}</div>
  182. <div class="label-item-value">
  183. <el-date-picker v-model="item.phenologyStartDate" type="date"
  184. :default-value="new Date(2026, 1, 1)" placeholder="选择时间" :disabled-date="disabledDate"
  185. :clearable="false" :editable="false" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
  186. style="width: 100%" />
  187. </div>
  188. </div>
  189. </div>
  190. </div>
  191. </div>
  192. <div class="period-footer">
  193. <div class="period-footer-btn" @click="handlePage">确认信息</div>
  194. </div>
  195. </popup>
  196. <tip-popup v-model:show="showSuccessPopup" type="success" text="专属处方已经生成" buttonText="点击查看"
  197. @closedPopup="handleSuccessConfirm" @confirm="handleSuccessConfirm">
  198. <template #default>
  199. <div class="expert-info">
  200. <!-- <img class="expert-img" src="@/assets/img/home/zj-1.png" alt=""> -->
  201. <el-avatar class="expert-img" :size="26" :src="basicForm?.expertInfo?.avatar" />
  202. {{ basicForm?.expertInfo?.name }} 专家的
  203. </div>
  204. </template>
  205. </tip-popup>
  206. </template>
  207. <script setup>
  208. import { ref, onActivated, onBeforeUnmount, onDeactivated, onMounted } from "vue";
  209. import { ElMessage } from "element-plus";
  210. import { useRouter, useRoute } from "vue-router";
  211. import tipPopup from "@/components/popup/tipPopup.vue";
  212. import customHeader from "@/components/customHeader.vue";
  213. import { Popup } from "vant";
  214. import { useStore } from "vuex";
  215. const router = useRouter();
  216. const route = useRoute();
  217. const store = useStore();
  218. // 农场规模
  219. const farmScale = ref({
  220. regularWorkerCount: "",
  221. plantProtectionWorkerCount: "",
  222. pruningWorkerCount: "",
  223. graftingWorkerCount: "",
  224. tempDispatchWorkerCount: "",
  225. });
  226. // 初始化默认选中第一项
  227. onActivated(() => {
  228. getBasicFarmFormData();
  229. // 为 productList 的每个 group 设置默认选中第一项
  230. });
  231. // onMounted(() => {
  232. // getCurrentAndNextPhenology();
  233. // });
  234. const loadingPage = ref(false);
  235. const basicForm = ref({
  236. soilTypes: "",
  237. irrigationMethods: [],
  238. machineryWithQuantity: [],
  239. improvementAreas: [],
  240. expertCode: "",
  241. expertInfo: {},
  242. });
  243. const basicFarmFormData = ref({});
  244. /** @param {{ machineryMerge?: { name: string, quantity?: string, unit?: string } }} [options] */
  245. const getBasicFarmFormData = (options = {}) => {
  246. const machineryMerge = options.machineryMerge;
  247. loadingPage.value = true;
  248. VE_API.basic_farm.fetchBasicFarmFormData({ subjectId: route.query?.subjectId }).then(({ data }) => {
  249. basicFarmFormData.value = data;
  250. // 根据返回的数据进行默认赋值
  251. // 1. 土壤类型 - 找到 selected: true 的项
  252. if (data.soilTypes && Array.isArray(data.soilTypes)) {
  253. const selectedSoilType = data.soilTypes.find(item => item.selected);
  254. if (selectedSoilType) {
  255. basicForm.value.soilTypes = selectedSoilType.code;
  256. }
  257. }
  258. // 2. 专家选项 - 找到 selected: true 的项
  259. if (data.expertOptions && Array.isArray(data.expertOptions)) {
  260. const selectedExpert = data.expertOptions.find(item => item.selected);
  261. if (selectedExpert) {
  262. basicForm.value.expertCode = selectedExpert.code;
  263. basicForm.value.expertInfo = selectedExpert;
  264. }
  265. }
  266. // 3. 农场规模数据
  267. if (data.farmScale) {
  268. farmScale.value = {
  269. regularWorkerCount: data.farmScale.regularWorkerCount || "",
  270. plantProtectionWorkerCount: data.farmScale.plantProtectionWorkerCount || "",
  271. pruningWorkerCount: data.farmScale.pruningWorkerCount || "",
  272. tempDispatchWorkerCount: data.farmScale.tempDispatchWorkerCount || "",
  273. graftingWorkerCount: data.farmScale.graftingWorkerCount || "",
  274. };
  275. }
  276. // 4. irrigationMethods, improvementAreas, machinery 的 selected 状态已经在 data 中设置好了
  277. // 这些数据会直接显示在页面上,因为页面是通过 basicFarmFormData 来渲染的
  278. // 新增「其它设备」时接口只存名称,刷新后把弹窗里填写的数量写回对应自定义项
  279. if (machineryMerge && Array.isArray(basicFarmFormData.value.machinery)) {
  280. const nameKey = (machineryMerge.name || "").trim();
  281. const row = basicFarmFormData.value.machinery.find(
  282. (m) => m.custom && String(m.name || "").trim() === nameKey
  283. );
  284. if (row) {
  285. row.selected = true;
  286. const q = (machineryMerge.quantity || "").trim();
  287. row.quantity = q || null;
  288. if (machineryMerge.unit) {
  289. row.unit = machineryMerge.unit;
  290. }
  291. }
  292. }
  293. }).finally(() => {
  294. loadingPage.value = false;
  295. });
  296. }
  297. // 收集表单数据并保存草稿
  298. const saveDraft = async () => {
  299. try {
  300. const draftData = handleSubmit();
  301. // 调用保存草稿接口
  302. await VE_API.basic_farm.saveDraft(draftData);
  303. } catch (error) {
  304. console.error("保存草稿失败:", error);
  305. // 静默失败,不显示错误提示
  306. }
  307. };
  308. // 离开页面时保存草稿
  309. onBeforeUnmount(() => {
  310. // saveDraft();
  311. });
  312. onDeactivated(() => {
  313. saveDraft();
  314. loading.value = false;
  315. });
  316. const formNameObj = ref({
  317. irrigationMethods: '灌溉方式',
  318. crops: '作物',
  319. machinery: '农机设备',
  320. improvementAreas: '希望专家帮助解决的种植难题',
  321. soilTypes: '土壤类型',
  322. });
  323. const showAddPopup = ref(false);
  324. const addTypeKey = ref("");
  325. const popupInputVal = ref("");
  326. // 农机设备数量
  327. const popupInputNum = ref("");
  328. const machineryUnit = ref("");
  329. const isEditPopup = ref(false);
  330. const currentEditIndex = ref(-1);
  331. function handleAdd(type) {
  332. isEditPopup.value = false;
  333. showAddPopup.value = true;
  334. addTypeKey.value = type;
  335. popupInputVal.value = "";
  336. popupInputNum.value = "";
  337. }
  338. function handleMachineryAdd(type) {
  339. handleAdd(type);
  340. isMachineSelf.value = true;
  341. }
  342. function handleSelect(type, index, custom) {
  343. isMachineSelf.value = custom;
  344. if (custom === true) {
  345. showAddPopup.value = true;
  346. isEditPopup.value = true;
  347. addTypeKey.value = type;
  348. popupInputVal.value = basicFarmFormData.value[type][index].name;
  349. currentEditIndex.value = index;
  350. }
  351. basicFarmFormData.value[type][index].selected = !basicFarmFormData.value[type][index].selected;
  352. }
  353. // 农机设备
  354. const isMachineSelf = ref(false);
  355. function handleMachinerySelect(type, index, item) {
  356. showAddPopup.value = true;
  357. isMachineSelf.value = item.custom;
  358. isEditPopup.value = item.selected || item.custom;
  359. addTypeKey.value = type;
  360. popupInputVal.value = item.name;
  361. popupInputNum.value = item.quantity;
  362. machineryUnit.value = item.unit;
  363. currentEditIndex.value = index;
  364. }
  365. function isPopupConfirmDisabled() {
  366. const nameFilled = String(popupInputVal.value ?? "").trim().length > 0;
  367. const quantityFilled = String(popupInputNum.value ?? "").trim().length > 0;
  368. // 仅需名称:非农机场景
  369. if (addTypeKey.value !== "machinery") {
  370. return !nameFilled;
  371. }
  372. // 仅需数量:选择已有农机(非自定义)
  373. if (!isMachineSelf.value) {
  374. return !quantityFilled;
  375. }
  376. // 名称 + 数量都必填:自定义农机
  377. return !(nameFilled && quantityFilled);
  378. }
  379. function handleConfirm() {
  380. if (isPopupConfirmDisabled()) {
  381. return;
  382. }
  383. if (addTypeKey.value === 'machinery') {
  384. if (isMachineSelf.value && !isEditPopup.value) {
  385. if (!popupInputVal.value.trim()) {
  386. return;
  387. }
  388. const nameTrim = popupInputVal.value.trim();
  389. saveCustomOption(nameTrim, {
  390. quantity: popupInputNum.value.trim(),
  391. unit: machineryUnit.value || undefined,
  392. });
  393. } else {
  394. const option = basicFarmFormData.value[addTypeKey.value][currentEditIndex.value]
  395. option.name = popupInputVal.value;
  396. const qtyTrim = (popupInputNum.value || "").trim();
  397. option.quantity = qtyTrim || null;
  398. option.selected = true;
  399. // 更新名称
  400. if (option.custom) {
  401. // updateCustomOption(popupInputVal.value, option.id || option.code);
  402. updateCustomOption(popupInputVal.value, basicFarmFormData.value[addTypeKey.value][currentEditIndex.value].id);
  403. }
  404. }
  405. currentEditIndex.value = -1;
  406. isEditPopup.value = false;
  407. showAddPopup.value = false;
  408. return;
  409. }
  410. if (!popupInputVal.value.trim()) {
  411. return;
  412. }
  413. if (isEditPopup.value) {
  414. const option = basicFarmFormData.value[addTypeKey.value][currentEditIndex.value]
  415. option.name = popupInputVal.value;
  416. currentEditIndex.value = -1;
  417. isEditPopup.value = false;
  418. showAddPopup.value = false;
  419. updateCustomOption(popupInputVal.value, option.id || option.code);
  420. return;
  421. }
  422. // basicFarmFormData.value[addTypeKey.value].push({ name: popupInputVal.value, code: popupInputVal.value, selected: true, custom: true });
  423. saveCustomOption(popupInputVal.value);
  424. showAddPopup.value = false;
  425. }
  426. const configTypeObj = {
  427. irrigationMethods: 'IRRIGATION',
  428. machinery: 'MACHINERY',
  429. }
  430. /** @param {{ quantity?: string, unit?: string }} [machineryMeta] 仅新增自定义农机时传入,用于刷新表单后合并数量 */
  431. function saveCustomOption(name, machineryMeta) {
  432. const cfgKey = addTypeKey.value;
  433. VE_API.basic_farm.addCustomOption({ configType: configTypeObj[cfgKey], name: name }).then(({ data }) => {
  434. ElMessage.success('保存成功');
  435. if (cfgKey === "machinery" && machineryMeta) {
  436. getBasicFarmFormData({
  437. machineryMerge: {
  438. name,
  439. quantity: machineryMeta.quantity,
  440. unit: machineryMeta.unit,
  441. },
  442. });
  443. } else {
  444. getBasicFarmFormData();
  445. }
  446. });
  447. }
  448. function updateCustomOption(name, id) {
  449. VE_API.basic_farm.updateCustomOption({ id, configType: configTypeObj[addTypeKey.value], name: name }).then(({ data }) => {
  450. ElMessage.success('保存成功');
  451. });
  452. }
  453. function handleDelete() {
  454. const option = basicFarmFormData.value[addTypeKey.value][currentEditIndex.value]
  455. VE_API.basic_farm.deleteCustomOption({ optionId: option.id || option.code }).then(({ data }) => {
  456. ElMessage.success('删除成功');
  457. basicFarmFormData.value[addTypeKey.value].splice(currentEditIndex.value, 1);
  458. currentEditIndex.value = -1;
  459. showAddPopup.value = false;
  460. });
  461. }
  462. function handleCancelSelect() {
  463. const option = basicFarmFormData.value[addTypeKey.value][currentEditIndex.value]
  464. option.selected = false;
  465. option.quantity = null;
  466. currentEditIndex.value = -1;
  467. showAddPopup.value = false;
  468. }
  469. const goBack = () => {
  470. // saveDraft();
  471. // router.go(-1);
  472. if (route.query.subjectId) {
  473. router.go(-1);
  474. } else {
  475. // router.replace(`/create_farm?from=${route.query.from}&type=edit`);
  476. router.replace(`/create_farm?from=${route.query.from}&type=${route.query.type}`);
  477. }
  478. };
  479. function handleSubmit() {
  480. // 收集土壤类型(转换为数组)
  481. const soilTypes = basicForm.value.soilTypes
  482. ? (Array.isArray(basicForm.value.soilTypes) ? basicForm.value.soilTypes : [basicForm.value.soilTypes])
  483. : [];
  484. // 收集灌溉方式(获取选中的 code)
  485. const irrigationMethods = (basicFarmFormData.value.irrigationMethods || [])
  486. .filter(item => item.selected || item.custom)
  487. .map(item => item.code || item.id);
  488. // 收集农机设备(包含 code 和 quantity)
  489. const machineryWithQuantity = (basicFarmFormData.value.machinery || [])
  490. .filter(item => item.selected)
  491. .map(item => ({
  492. code: item.code || item.id,
  493. quantity: Number(item.quantity) || 0
  494. }));
  495. // 收集希望专家帮助解决的种植难题(获取选中的 code)
  496. const improvementAreas = (basicFarmFormData.value.improvementAreas || [])
  497. .filter(item => item.selected)
  498. .map(item => item.code || item.id);
  499. // 收集农场规模数据
  500. const draftData = {
  501. soilTypes: soilTypes.map(code => Number(code)),
  502. irrigationMethods: irrigationMethods.map(code => Number(code)),
  503. machineryWithQuantity: machineryWithQuantity.map(item => ({
  504. code: Number(item.code),
  505. quantity: item.quantity
  506. })),
  507. regularWorkerCount: Number(farmScale.value.regularWorkerCount) || 0,
  508. plantProtectionWorkerCount: Number(farmScale.value.plantProtectionWorkerCount) || 0,
  509. pruningWorkerCount: Number(farmScale.value.pruningWorkerCount) || 0,
  510. graftingWorkerCount: Number(farmScale.value.graftingWorkerCount) || 0,
  511. tempDispatchWorkerCount: Number(farmScale.value.tempDispatchWorkerCount) || 0,
  512. improvementAreas: improvementAreas.map(code => Number(code)),
  513. };
  514. // 如果有选择的专家,添加 preferredExpertCode
  515. if (basicForm.value.expertCode) {
  516. draftData.preferredExpertCode = Number(basicForm.value.expertCode);
  517. }
  518. return draftData;
  519. }
  520. // 校验必填项
  521. function validateForm() {
  522. // 校验土壤类型
  523. if (!basicForm.value.soilTypes) {
  524. ElMessage.warning('请选择您的果园土壤类型');
  525. return false;
  526. }
  527. // 校验灌溉方式
  528. const irrigationMethods = (basicFarmFormData.value.irrigationMethods || [])
  529. .filter(item => item.selected);
  530. if (irrigationMethods.length === 0) {
  531. ElMessage.warning('请选择您的灌溉方式');
  532. return false;
  533. }
  534. // 校验农机设备(仅要求有选中项,数量选填)
  535. const machinerySelected = (basicFarmFormData.value.machinery || [])
  536. .filter(item => item.selected);
  537. if (machinerySelected.length === 0) {
  538. ElMessage.warning('请选择您的农机设备');
  539. return false;
  540. }
  541. // 校验希望专家帮助解决的种植难题
  542. const improvementAreas = (basicFarmFormData.value.improvementAreas || [])
  543. .filter(item => item.selected);
  544. if (improvementAreas.length === 0) {
  545. ElMessage.warning('请选择希望专家帮助解决的种植难题');
  546. return false;
  547. }
  548. // 校验专家选项
  549. if (!basicForm.value.expertCode) {
  550. ElMessage.warning('请选择您最希望得到哪位荔枝专家的农事处方');
  551. return false;
  552. }
  553. return true;
  554. }
  555. const showSuccessPopup = ref(false);
  556. const handleSuccessConfirm = () => {
  557. router.push('/agri_record');
  558. }
  559. const loading = ref(false);
  560. async function submit() {
  561. try {
  562. // 正式提交
  563. const draftData = handleSubmit();
  564. // const params = {
  565. // ...route.query,
  566. // phenologyId: phenologyList.value[0].phenologyId,
  567. // phenologyStartDate: phenologyList.value[0].phenologyStartDate,
  568. // basicInfo: draftData,
  569. // expertMiniUserId: '81881',
  570. // }
  571. // const res = await VE_API.basic_farm.saveBasicFarmInfoByExpert(params);
  572. let paramsData = null
  573. if (route.query.subjectId) {
  574. paramsData = {
  575. ...draftData,
  576. subjectId: route.query.subjectId,
  577. }
  578. } else {
  579. paramsData = {
  580. ...route.query,
  581. expertMiniUserId: '81881',
  582. basicInfo: draftData,
  583. speciesContainer: JSON.parse(route.query.speciesContainer),
  584. }
  585. }
  586. loading.value = true;
  587. const apiCall = route.query.subjectId ? VE_API.basic_farm.saveBasicFarmInfo(paramsData) : VE_API.basic_farm.saveBasicFarmInfoByExpertV3(paramsData);
  588. apiCall.then((res) => {
  589. loading.value = false;
  590. if (res.code === 0) {
  591. // showSuccessPopup.value = true;
  592. if (route.query.subjectId) {
  593. router.go(-1);
  594. } else {
  595. // 设置选中当前新增的农场
  596. localStorage.setItem("selectedFarmId", res.data.id);
  597. localStorage.setItem("selectedFarmName", res.data.name);
  598. router.replace('/growth_report');
  599. }
  600. ElMessage.success('创建成功');
  601. // return true;
  602. } else {
  603. ElMessage.error(res.msg || '提交失败,请重试');
  604. return false;
  605. }
  606. })
  607. } catch (error) {
  608. loading.value = false;
  609. console.error('提交失败:', error);
  610. ElMessage.error('提交失败,请重试');
  611. return false;
  612. }
  613. }
  614. const showPeriodPopup = ref(false);
  615. const phenologyList = ref([]);
  616. const disabledDate = (time) => {
  617. // 获取今天的开始时间(00:00:00)
  618. const today = new Date();
  619. today.setHours(0, 0, 0, 0);
  620. // 获取明天的开始时间(00:00:00)
  621. const tomorrow = new Date(today);
  622. tomorrow.setDate(tomorrow.getDate() + 1);
  623. // 设置最小日期为 2025-01-01
  624. const minDate = new Date(2025, 10, 1); // 月份从0开始,0表示1月
  625. minDate.setHours(0, 0, 0, 0);
  626. // 如果时间 < 2025-10-01 或 >= 明天的开始时间,则禁用
  627. // 只能选择 2025-10-01 到今天的日期范围
  628. return time.getTime() < minDate.getTime() || time.getTime() >= tomorrow.getTime();
  629. }
  630. const handlePage = async () => {
  631. try {
  632. // 先进行校验
  633. if (!validateForm()) {
  634. return;
  635. }
  636. // 安全解析 typeNames
  637. // let typeNames = [];
  638. // try {
  639. // if (route.query.typeNames) {
  640. // typeNames = JSON.parse(route.query.typeNames);
  641. // } else {
  642. // ElMessage.warning('缺少必要参数,请重新进入页面');
  643. // return;
  644. // }
  645. // } catch (e) {
  646. // console.error('解析 typeNames 失败:', e);
  647. // ElMessage.warning('参数格式错误,请重新进入页面');
  648. // return;
  649. // }
  650. // // 检查 firstPhenology 是否已初始化
  651. // if (!firstPhenology.value || !firstPhenology.value.phenologyId) {
  652. // ElMessage.warning('物候期数据未加载完成,请稍候再试');
  653. // return;
  654. // }
  655. // phenologyList.value = typeNames.map(item => ({
  656. // typeName: item,
  657. // phenologyId: firstPhenology.value.phenologyId,
  658. // startDateLabel: firstPhenology.value.startDateLabel,
  659. // phenologyName: firstPhenology.value.phenologyName,
  660. // phenologyStartDate: '2026-01-01',
  661. // }));
  662. // 如果有选择的专家,添加 preferredExpertCode
  663. if (basicForm.value.expertCode) {
  664. const selectedExpert = basicFarmFormData.value.expertOptions?.find(item => item.code === basicForm.value.expertCode);
  665. if (selectedExpert) {
  666. basicForm.value.expertInfo = selectedExpert;
  667. }
  668. }
  669. showPeriodPopup.value = true;
  670. } catch (error) {
  671. console.error('handlePage 执行失败:', error);
  672. ElMessage.error('操作失败,请重试');
  673. }
  674. };
  675. // 获取当前日期(YYYY-MM-DD格式)
  676. const getTodayDate = () => {
  677. const today = new Date();
  678. const year = today.getFullYear();
  679. const month = String(today.getMonth() + 1).padStart(2, "0");
  680. const day = String(today.getDate()).padStart(2, "0");
  681. return `${year}-${month}-${day}`;
  682. };
  683. const firstPhenology = ref({});
  684. const phenologyData = ref({});
  685. // 从 query 中解析 containerId(支持 speciesContainer 数组/对象或 JSON 字符串)
  686. const getContainerIdFromQuery = () => {
  687. const sc = route.query.speciesContainer;
  688. if (sc != null) {
  689. const parsed = typeof sc === 'string' ? (tryParse(sc) || []) : sc;
  690. const first = Array.isArray(parsed) ? parsed[0] : parsed;
  691. return first?.containerId ?? route.query.containerId;
  692. }
  693. return route.query.containerId;
  694. };
  695. const tryParse = (str) => {
  696. try { return JSON.parse(str); } catch { return null; }
  697. };
  698. // 获取当前和下一个物候期
  699. const getCurrentAndNextPhenology = async () => {
  700. try {
  701. const { data } = await VE_API.home.getCurrentAndNextPhenology({
  702. expertMiniUserId: '81881',
  703. containerId: getContainerIdFromQuery(),
  704. });
  705. if (data && Array.isArray(data)) {
  706. // 初始化物候期表单数据,日期使用第一个物候期的 startDate
  707. firstPhenology.value = data[0];
  708. }
  709. } catch (error) {
  710. console.error("获取物候期数据失败", error);
  711. ElMessage.error("获取物候期数据失败");
  712. }
  713. };
  714. // 确认物候期信息
  715. const handlePeriodConfirm = async () => {
  716. // 校验所有物候期信息是否填写完整
  717. const hasEmptyDate = phenologyList.value.some(item => !item.phenologyStartDate);
  718. if (hasEmptyDate) {
  719. ElMessage.warning('请选择时间');
  720. return;
  721. }
  722. // 关闭弹窗并提交表单
  723. showPeriodPopup.value = false;
  724. loadingPage.value = true;
  725. // 正式提交
  726. const success = await submit();
  727. loadingPage.value = false;
  728. if (!success) {
  729. return;
  730. }
  731. // 提交成功后跳转
  732. // if (route.query.type === 'farmer') {
  733. // router.push('/agri_record')
  734. // return
  735. // }
  736. // // 获取所有需要传递的参数,包括 from 参数
  737. // const queryParams = {
  738. // containerId: route.query.containerId,
  739. // };
  740. // // 如果存在 from 参数,继续传递
  741. // if (route.query.from) {
  742. // queryParams.from = route.query.from;
  743. // }
  744. // // 传递所有农场相关的参数,以便在 agricultural_plan 页面创建农场
  745. // const farmParams = ['wkt', 'speciesId', 'containerId', 'agriculturalCreate', 'geom', 'address', 'mu', 'name', 'fzr', 'tel', 'defaultFarm', 'typeId', 'speciesName', 'userType'];
  746. // farmParams.forEach(key => {
  747. // if (route.query[key] !== undefined) {
  748. // queryParams[key] = route.query[key];
  749. // }
  750. // });
  751. // router.push({
  752. // path: '/agricultural_plan',
  753. // query: queryParams
  754. // });
  755. };
  756. </script>
  757. <style lang="scss" scoped>
  758. .prescription-page {
  759. position: relative;
  760. width: 100%;
  761. height: calc(100vh - 62px);
  762. overflow: auto;
  763. box-sizing: border-box;
  764. background: linear-gradient(to left, #e6f2ff, #8fc5fe);
  765. .page-content {
  766. height: calc(100% - 40px);
  767. overflow: auto;
  768. box-sizing: border-box;
  769. }
  770. .prescription-title {
  771. padding: 26px 14px 10px 14px;
  772. background: url("@/assets/img/home/page-bg.png") no-repeat bottom right / 141px 116px;
  773. background-position-y: 7px;
  774. img {
  775. width: 24px;
  776. }
  777. .title-name {
  778. font-size: 22px;
  779. color: #2e2e2e;
  780. text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05);
  781. font-weight: 500;
  782. padding: 0 0 4px 6px;
  783. }
  784. .title-desc {
  785. font-size: 14px;
  786. color: rgba(49, 49, 49, 0.56);
  787. padding-left: 6px;
  788. }
  789. }
  790. .prescription-box {
  791. background: #ffffff;
  792. box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1);
  793. border-radius: 10px;
  794. margin: 0 10px 30px 10px;
  795. box-sizing: border-box;
  796. padding-bottom: 10px;
  797. .box-title {
  798. margin: 0 10px;
  799. box-sizing: border-box;
  800. border-bottom: 1px solid rgba(0, 0, 0, 0.15);
  801. font-weight: 800;
  802. font-size: 18px;
  803. color: #222222;
  804. padding: 15px 0 10px;
  805. img {
  806. width: 14px;
  807. height: 9px;
  808. }
  809. }
  810. .pt-16 {
  811. padding-top: 16px;
  812. }
  813. .box-content {
  814. padding: 0 10px;
  815. .box-item {
  816. padding-top: 16px;
  817. .item-name {
  818. display: flex;
  819. align-items: center;
  820. font-size: 14px;
  821. color: rgba(0, 0, 0, 0.9);
  822. font-weight: 500;
  823. .required-icon {
  824. color: #ff0000;
  825. font-size: 16px;
  826. margin-right: 4px;
  827. }
  828. .sub-name {
  829. font-size: 12px;
  830. font-weight: 400;
  831. }
  832. }
  833. .tips {
  834. // margin-left: 10px;
  835. font-size: 12px;
  836. color: rgba(0, 0, 0, 0.4);
  837. }
  838. .item-checkbox {
  839. .tag-group {
  840. display: grid;
  841. grid-template-columns: repeat(3, 1fr);
  842. gap: 0 7px;
  843. font-size: 14px;
  844. .tag-item {
  845. margin-top: 10px;
  846. position: relative;
  847. border-radius: 4px;
  848. color: #2199f8;
  849. // padding: 0 4px;
  850. box-sizing: border-box;
  851. // min-width: 26vw;
  852. height: 40px;
  853. text-align: center;
  854. line-height: 40px;
  855. cursor: pointer;
  856. transition: all 0.3s;
  857. .quantity-text {
  858. font-size: 10px;
  859. color: #fff;
  860. position: absolute;
  861. right: -7px;
  862. top: -7px;
  863. width: 14px;
  864. text-align: center;
  865. line-height: 14px;
  866. height: 14px;
  867. border-radius: 50%;
  868. background: #2199F8;
  869. }
  870. .text {
  871. display: inline-flex;
  872. align-items: center;
  873. }
  874. .edit-icon {
  875. margin-left: 8px;
  876. }
  877. .del-icon {
  878. position: absolute;
  879. right: -8px;
  880. top: -8px;
  881. background: #2199F8;
  882. border-radius: 50%;
  883. width: 16px;
  884. height: 16px;
  885. font-size: 10px;
  886. display: flex;
  887. align-items: center;
  888. justify-content: center;
  889. color: #fff;
  890. }
  891. &.selected {
  892. border: 1px solid #2199F8;
  893. background: #E8F5FF;
  894. color: #2199F8;
  895. &::after {
  896. content: "";
  897. position: absolute;
  898. z-index: 9;
  899. bottom: -1px;
  900. right: 0;
  901. width: 18px;
  902. height: 13px;
  903. background: url("@/assets/img/home/checked-bg.png") no-repeat bottom right / 18px 13px;
  904. }
  905. }
  906. }
  907. &.add-tag-group {
  908. .tag-item {
  909. color: #000000;
  910. background: rgba(241, 241, 241, 0.12);
  911. border: 1px solid #EBEBEB;
  912. cursor: pointer;
  913. &.self {
  914. border: 1px solid #2199F8;
  915. background: #E8F5FF;
  916. color: #2199F8;
  917. &::after {
  918. content: "";
  919. position: absolute;
  920. z-index: 9;
  921. bottom: -1px;
  922. right: 0;
  923. width: 18px;
  924. height: 13px;
  925. background: url("@/assets/img/home/checked-bg.png") no-repeat bottom right / 18px 13px;
  926. }
  927. }
  928. &.selected {
  929. border: 1px solid #2199F8;
  930. background: #E8F5FF;
  931. color: #2199F8;
  932. }
  933. &.last-add {
  934. // background: #F7F7F7;
  935. // color: #343434;
  936. // border: none;
  937. display: flex;
  938. align-items: center;
  939. justify-content: center;
  940. cursor: pointer;
  941. .add-icon {
  942. font-size: 14px;
  943. font-weight: bold;
  944. margin-right: 3px;
  945. }
  946. }
  947. }
  948. }
  949. }
  950. ::v-deep {
  951. .el-radio-button,
  952. .el-checkbox-button {
  953. margin: 10px 0 0 7px;
  954. .el-radio-button__inner,
  955. .el-checkbox-button__inner {
  956. border: none;
  957. border-radius: 6px;
  958. // padding: 13px 21px;
  959. height: 40px;
  960. width: 104px;
  961. display: flex;
  962. align-items: center;
  963. justify-content: center;
  964. border: 1px solid #EBEBEB;
  965. color: #000000;
  966. background: rgba(241, 241, 241, 0.12);
  967. font-weight: 400;
  968. }
  969. &.is-active,
  970. &.is-checked {
  971. &::after {
  972. content: "";
  973. position: absolute;
  974. z-index: 9;
  975. bottom: -0.5px;
  976. right: 0;
  977. width: 18px;
  978. height: 13px;
  979. background: url("@/assets/img/home/checked-bg.png") no-repeat bottom right / 18px 13px;
  980. }
  981. .el-radio-button__inner,
  982. .el-checkbox-button__inner {
  983. background: rgba(33, 153, 248, 0.1) !important;
  984. color: #2199f8 !important;
  985. border: 1px solid #2199f8 !important;
  986. box-shadow: none;
  987. }
  988. }
  989. &.is-active {
  990. .el-radio-button__original-radio:not(:disabled)+.el-radio-button__inner {
  991. background: rgba(33, 153, 248, 0.1) !important;
  992. color: #2199f8 !important;
  993. border: 1px solid #2199f8 !important;
  994. box-shadow: none;
  995. font-weight: 500;
  996. }
  997. }
  998. &.is-checked {
  999. .el-checkbox-button__original-checkbox:not(:disabled)+.el-checkbox-button__inner {
  1000. background: rgba(33, 153, 248, 0.1) !important;
  1001. color: #2199f8 !important;
  1002. border: 1px solid #2199f8 !important;
  1003. box-shadow: none;
  1004. font-weight: 500;
  1005. }
  1006. }
  1007. }
  1008. .el-radio-button:nth-child(3n-2) {
  1009. margin-left: 0;
  1010. }
  1011. }
  1012. }
  1013. }
  1014. }
  1015. /* 农场规模(与农场情况同一卡片内) */
  1016. .farm-scale-header {
  1017. margin-top: 16px;
  1018. .farm-scale-title {
  1019. font-size: 15px;
  1020. font-weight: 500;
  1021. color: rgba(0, 0, 0, 0.9);
  1022. }
  1023. .farm-scale-desc {
  1024. font-size: 13px;
  1025. color: rgba(0, 0, 0, 0.4);
  1026. }
  1027. }
  1028. .farm-scale-form {
  1029. margin-top: 10px;
  1030. border: 0.5px solid rgba(33, 153, 248, 0.5);
  1031. border-radius: 8px;
  1032. padding: 10px;
  1033. .farm-scale-item {
  1034. display: flex;
  1035. align-items: center;
  1036. margin-bottom: 14px;
  1037. &:last-child {
  1038. margin-bottom: 0;
  1039. }
  1040. .farm-scale-label {
  1041. flex-shrink: 0;
  1042. width: 116px;
  1043. font-size: 14px;
  1044. color: rgba(0, 0, 0, 0.9);
  1045. // text-align: right;
  1046. margin-right: 10px;
  1047. .sub-label {
  1048. font-size: 10px;
  1049. color: rgba(0, 0, 0, 0.4);
  1050. line-height: 15px;
  1051. }
  1052. }
  1053. .farm-scale-input {
  1054. flex: 1;
  1055. ::v-deep .el-input-group__append {
  1056. padding: 0 12px;
  1057. background: #f5f7fa;
  1058. color: rgba(0, 0, 0, 0.65);
  1059. border-color: #dcdfe6;
  1060. border-radius: 0 4px 4px 0;
  1061. }
  1062. ::v-deep .el-input__inner {
  1063. border-radius: 4px 0 0 4px;
  1064. }
  1065. }
  1066. }
  1067. }
  1068. }
  1069. .disaster-desc-box {
  1070. padding: 10px;
  1071. display: flex;
  1072. align-items: center;
  1073. span {
  1074. font-size: 14px;
  1075. color: rgba(0, 0, 0, 0.9);
  1076. width: 80px;
  1077. }
  1078. }
  1079. }
  1080. .add-tag-popup {
  1081. width: 90%;
  1082. padding: 24px 16px 20px 16px;
  1083. background: linear-gradient(360deg, #FFFFFF 74.2%, #D1EBFF 100%);
  1084. .popup-title {
  1085. font-size: 16px;
  1086. font-weight: 400;
  1087. margin-bottom: 12px;
  1088. color: #000000;
  1089. .name-text {
  1090. font-weight: 500;
  1091. color: #2199F8;
  1092. padding: 0 2px;
  1093. }
  1094. }
  1095. .ml-2 {
  1096. margin-left: 3px;
  1097. }
  1098. .popup-input {
  1099. margin-bottom: 24px;
  1100. }
  1101. .popup-button {
  1102. display: flex;
  1103. div {
  1104. flex: 1;
  1105. font-size: 16px;
  1106. padding: 9px;
  1107. border-radius: 20px;
  1108. background: #2199F8;
  1109. color: #fff;
  1110. text-align: center;
  1111. cursor: pointer;
  1112. }
  1113. .cancel {
  1114. margin-right: 13px;
  1115. color: #000;
  1116. background: #fff;
  1117. border: 1px solid #999999;
  1118. }
  1119. .disabled {
  1120. opacity: 0.5;
  1121. cursor: not-allowed;
  1122. }
  1123. .delete {
  1124. margin-right: 13px;
  1125. color: #FF3D3D;
  1126. background: #fff;
  1127. border: 1px solid rgba(255, 61, 61, 0.4);
  1128. }
  1129. }
  1130. }
  1131. .period-popup {
  1132. width: 90%;
  1133. padding: 24px 16px 20px 16px;
  1134. background: linear-gradient(360deg, #FFFFFF 74.2%, #D1EBFF 100%);
  1135. .period-header {
  1136. font-size: 16px;
  1137. font-weight: 400;
  1138. margin-bottom: 16px;
  1139. color: #121212;
  1140. line-height: 22px;
  1141. }
  1142. .period-content {
  1143. margin-bottom: 16px;
  1144. .period-item {
  1145. background: rgba(33, 153, 248, 0.05);
  1146. border: 1px solid rgba(33, 153, 248, 0.2);
  1147. border-radius: 5px;
  1148. padding: 10px;
  1149. margin-bottom: 16px;
  1150. position: relative;
  1151. &:last-child {
  1152. margin-bottom: 0;
  1153. }
  1154. .period-item-name {
  1155. background: rgba(33, 153, 248, 0.1);
  1156. font-size: 12px;
  1157. color: #2199F8;
  1158. padding: 2px 10px;
  1159. border-radius: 2px;
  1160. font-weight: 400;
  1161. width: fit-content;
  1162. }
  1163. .period-item-label {
  1164. margin-top: 10px;
  1165. .label-item-group {
  1166. display: flex;
  1167. align-items: center;
  1168. margin-bottom: 12px;
  1169. &:last-child {
  1170. margin-bottom: 0;
  1171. }
  1172. .label-item {
  1173. font-size: 14px;
  1174. color: #1D2129;
  1175. min-width: 100px;
  1176. flex-shrink: 0;
  1177. padding-right: 10px;
  1178. }
  1179. .label-item-value {
  1180. border-radius: 2px;
  1181. flex: 1;
  1182. font-size: 14px;
  1183. color: #1D2129;
  1184. min-height: 31px;
  1185. line-height: 31px;
  1186. display: flex;
  1187. align-items: center;
  1188. &.period-display {
  1189. background: #FFFFFF;
  1190. border: 0.5px solid rgba(0, 0, 0, 0.2);
  1191. padding: 0 8px;
  1192. }
  1193. }
  1194. }
  1195. }
  1196. }
  1197. }
  1198. .period-footer {
  1199. .period-footer-btn {
  1200. width: 100%;
  1201. background: #2199F8;
  1202. color: #ffffff;
  1203. font-size: 16px;
  1204. text-align: center;
  1205. height: 40px;
  1206. line-height: 40px;
  1207. border-radius: 4px;
  1208. cursor: pointer;
  1209. font-weight: 500;
  1210. &:active {
  1211. opacity: 0.8;
  1212. }
  1213. }
  1214. }
  1215. }
  1216. .expert-info {
  1217. display: flex;
  1218. align-items: center;
  1219. justify-content: center;
  1220. font-size: 20px;
  1221. line-height: 36px;
  1222. .expert-img {
  1223. // width: 26px;
  1224. // height: 26px;
  1225. // border-radius: 50%;
  1226. // object-fit: cover;
  1227. margin-right: 5px;
  1228. }
  1229. }
  1230. // 优化按钮点击体验,解决移动端点击无响应问题
  1231. .custom-bottom-fixed-btns {
  1232. z-index: 99 !important; // 提高 z-index,确保不被其他元素遮挡
  1233. pointer-events: auto; // 确保可以接收点击事件
  1234. .bottom-btn {
  1235. height: 40px;
  1236. padding: 0 30px;
  1237. line-height: 40px;
  1238. cursor: pointer;
  1239. user-select: none; // 防止文本选择
  1240. touch-action: manipulation; // 优化移动端触摸响应
  1241. -webkit-tap-highlight-color: transparent; // 移除移动端点击高亮
  1242. position: relative; // 确保点击区域正确
  1243. z-index: 1;
  1244. // 添加点击反馈效果
  1245. &:active {
  1246. opacity: 0.8;
  1247. transform: scale(0.98);
  1248. }
  1249. &.primary-btn {
  1250. // 确保按钮可点击
  1251. pointer-events: auto;
  1252. }
  1253. }
  1254. }
  1255. </style>
  1256. <style lang="scss">
  1257. .el-message--warning .el-message__content {
  1258. line-height: 20px;
  1259. }
  1260. </style>