index.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <template>
  2. <div class="service-manage">
  3. <custom-header name="服务维护"></custom-header>
  4. <ServiceInfo
  5. ref="serviceInfoRef"
  6. v-model:crops="crops"
  7. v-model:serviceTypes="serviceTypes"
  8. v-model:machines="machines"
  9. v-model:isEdit="isEdit"
  10. />
  11. <div class="page-action" v-if="isEdit">
  12. <div class="btn-item cancel" @click="isEdit = false">取消</div>
  13. <div class="btn-right">
  14. <div class="btn-item primary" @click="handleSave">保存服务类型</div>
  15. </div>
  16. </div>
  17. <div class="page-action" v-else>
  18. <div class="btn-item primary center-btn" @click="isEdit = true">编辑服务类型</div>
  19. </div>
  20. </div>
  21. </template>
  22. <script setup>
  23. import { ref, onMounted, onActivated, watch } from "vue";
  24. import customHeader from "@/components/customHeader.vue";
  25. import ServiceInfo from "@/components/pageComponents/ServiceInfo.vue";
  26. import { ElMessage } from "element-plus";
  27. const isEdit = ref(false);
  28. const serviceInfoRef = ref(null);
  29. // 默认数据
  30. const defaultCrops = [
  31. { name: "荔枝", isSelf: 0 },
  32. { name: "水稻", isSelf: 0 },
  33. { name: "菠萝", isSelf: 0 },
  34. { name: "柚子", isSelf: 0 },
  35. { name: "蔬菜", isSelf: 0 },
  36. { name: "小麦", isSelf: 0 },
  37. ];
  38. const defaultServiceTypes = [
  39. { name: "嫁接", isSelf: 0 },
  40. { name: "施肥打药", isSelf: 0 },
  41. { name: "修剪", isSelf: 0 },
  42. ];
  43. const defaultMachines = [
  44. { name: "植保机", isSelf: 0 },
  45. { name: "喷药车", isSelf: 0 },
  46. { name: "收割机", isSelf: 0 }
  47. ];
  48. // 三类数据:数组对象形式
  49. const crops = ref([]);
  50. const serviceTypes = ref([]);
  51. const machines = ref([]);
  52. // 将接口返回的字符串数组转换为对象数组(默认显示时使用)
  53. function convertApiDataToItems(apiList) {
  54. if (!Array.isArray(apiList)) {
  55. return [];
  56. }
  57. return apiList.map(item => {
  58. const name = typeof item === 'string' ? item : (item.name || item);
  59. // 检查是否是默认数据中的项
  60. const isDefault = defaultCrops.some(d => d.name === name) ||
  61. defaultServiceTypes.some(d => d.name === name) ||
  62. defaultMachines.some(d => d.name === name);
  63. return {
  64. name: name,
  65. isSelf: isDefault ? 0 : 1, // 如果是默认数据中的,isSelf=0,否则是用户自定义的
  66. selected: true // 接口返回的都是已保存的,所以都选中
  67. };
  68. });
  69. }
  70. // 合并数据:编辑时将默认数据与接口数据合并,name相同的设置为选中
  71. function mergeDataForEdit(defaultList, apiList) {
  72. // 创建 API 返回数据的名称集合(用于判断是否选中)
  73. const apiNameSet = new Set(apiList.map(item => typeof item === 'string' ? item : (item.name || item)));
  74. // 合并逻辑:默认数据 + API 数据(去重)
  75. const merged = [...defaultList];
  76. // 标记默认数据中哪些被选中(name 在 API 数据中存在)
  77. merged.forEach(item => {
  78. if (apiNameSet.has(item.name)) {
  79. item.selected = true;
  80. } else {
  81. item.selected = false;
  82. }
  83. });
  84. // 添加 API 中存在但默认数据中不存在的项(这些是用户自定义的)
  85. apiList.forEach(apiItem => {
  86. const apiName = typeof apiItem === 'string' ? apiItem : (apiItem.name || apiItem);
  87. const exists = merged.some(item => item.name === apiName);
  88. if (!exists) {
  89. merged.push({
  90. name: apiName,
  91. isSelf: 1, // 标记为用户自定义
  92. selected: true
  93. });
  94. }
  95. });
  96. return merged;
  97. }
  98. // 获取服务详情
  99. function getServiceDetail() {
  100. VE_API.z_agricultural_store.getServiceDetail().then(({ data }) => {
  101. if (data) {
  102. // 默认情况下,只显示接口返回的数据
  103. crops.value = convertApiDataToItems(data.serviceCropsJson || []);
  104. serviceTypes.value = convertApiDataToItems(data.serviceTypeJson || []);
  105. machines.value = convertApiDataToItems(data.agriculturalEquipmentJson || []);
  106. } else {
  107. // 如果没有数据,显示空数组
  108. crops.value = [];
  109. serviceTypes.value = [];
  110. machines.value = [];
  111. }
  112. }).catch(() => {
  113. // 获取失败,显示空数组
  114. crops.value = [];
  115. serviceTypes.value = [];
  116. machines.value = [];
  117. });
  118. }
  119. // 监听编辑状态,编辑时合并默认数据
  120. watch(isEdit, (newVal) => {
  121. if (newVal) {
  122. // 进入编辑模式,合并默认数据
  123. VE_API.z_agricultural_store.getServiceDetail().then(({ data }) => {
  124. if (data) {
  125. crops.value = mergeDataForEdit(defaultCrops, data.serviceCropsJson || []);
  126. serviceTypes.value = mergeDataForEdit(defaultServiceTypes, data.serviceTypeJson || []);
  127. machines.value = mergeDataForEdit(defaultMachines, data.agriculturalEquipmentJson || []);
  128. } else {
  129. // 如果没有数据,使用默认数据(都不选中)
  130. crops.value = defaultCrops.map(item => ({ ...item, selected: false }));
  131. serviceTypes.value = defaultServiceTypes.map(item => ({ ...item, selected: false }));
  132. machines.value = defaultMachines.map(item => ({ ...item, selected: false }));
  133. }
  134. }).catch(() => {
  135. // 获取失败,使用默认数据(都不选中)
  136. crops.value = defaultCrops.map(item => ({ ...item, selected: false }));
  137. serviceTypes.value = defaultServiceTypes.map(item => ({ ...item, selected: false }));
  138. machines.value = defaultMachines.map(item => ({ ...item, selected: false }));
  139. });
  140. } else {
  141. // 退出编辑模式,重新获取数据(只显示接口返回的数据)
  142. getServiceDetail();
  143. }
  144. });
  145. // 保存服务类型
  146. function handleSave() {
  147. if (!serviceInfoRef.value) {
  148. return;
  149. }
  150. const serviceInfo = serviceInfoRef.value.getServiceInfo();
  151. VE_API.z_agricultural_store.updateService({
  152. serviceCropsJson: serviceInfo.serviceCropsJson,
  153. serviceTypeJson: serviceInfo.serviceTypeJson,
  154. agriculturalEquipmentJson: serviceInfo.agriculturalEquipmentJson
  155. }).then(({ code, msg }) => {
  156. if (code === 0) {
  157. ElMessage.success("保存成功");
  158. isEdit.value = false;
  159. // 重新获取数据
  160. getServiceDetail();
  161. } else {
  162. ElMessage.error(msg || "保存失败");
  163. }
  164. }).catch(() => {
  165. ElMessage.error("保存失败,请重试");
  166. });
  167. }
  168. onMounted(() => {
  169. getServiceDetail();
  170. });
  171. onActivated(() => {
  172. getServiceDetail();
  173. });
  174. </script>
  175. <style lang="scss" scoped>
  176. .service-manage {
  177. width: 100%;
  178. height: 100vh;
  179. background: #F5F7FB;
  180. .page-action {
  181. position: fixed;
  182. left: 0;
  183. right: 0;
  184. bottom: 0;
  185. padding: 12px 12px;
  186. background: #fff;
  187. box-shadow: 2px 2px 4.5px rgba(0, 0, 0, 0.4);
  188. display: flex;
  189. justify-content: space-between;
  190. align-items: center;
  191. .btn-item {
  192. height: 40px;
  193. line-height: 41px;
  194. border-radius: 20px;
  195. width: fit-content;
  196. padding: 0 20px;
  197. color: #666666;
  198. font-size: 14px;
  199. &.del {
  200. color: #ff943d;
  201. background: rgba(255, 148, 61, 0.1);
  202. }
  203. &.cancel {
  204. border: 1px solid rgba(153, 153, 153, 0.5);
  205. }
  206. &.primary {
  207. color: #fff;
  208. background: linear-gradient(#76c3ff, #2199f8);
  209. }
  210. }
  211. .center-btn {
  212. margin: 0 auto;
  213. }
  214. .btn-right {
  215. display: flex;
  216. gap: 10px;
  217. }
  218. }
  219. }
  220. </style>