index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. <template>
  2. <div class="planting-page">
  3. <div class="page-card">
  4. <!-- 顶部:Tab -->
  5. <div class="page-header">
  6. <div class="page-tabs">
  7. <div
  8. v-for="tab in tabs"
  9. :key="tab.value"
  10. class="page-tabs__item"
  11. :class="{ 'is-active': activeTab === tab.value }"
  12. @click="activeTab = tab.value"
  13. >
  14. {{ tab.label }}
  15. </div>
  16. </div>
  17. </div>
  18. <!-- 种植方案 -->
  19. <template v-if="activeTab === 'scheme'">
  20. <div class="filter-panel">
  21. <div class="filter-row">
  22. <span class="filter-label">区域:</span>
  23. <div class="filter-content region-selects">
  24. <el-select v-model="filters.province" placeholder="选择省份" clearable class="region-select">
  25. <el-option
  26. v-for="item in provinceOptions"
  27. :key="item.value"
  28. :label="item.label"
  29. :value="item.value"
  30. />
  31. </el-select>
  32. <el-select v-model="filters.city" placeholder="选择城市" clearable class="region-select">
  33. <el-option
  34. v-for="item in cityOptions"
  35. :key="item.value"
  36. :label="item.label"
  37. :value="item.value"
  38. />
  39. </el-select>
  40. </div>
  41. </div>
  42. <div class="filter-row">
  43. <span class="filter-label">品类:</span>
  44. <div class="filter-content tag-list">
  45. <div
  46. v-for="(item, idx) in categoryOptions"
  47. :key="`category-${idx}`"
  48. class="filter-tag"
  49. :class="{ 'is-active': filters.categoryIndex === idx }"
  50. @click="filters.categoryIndex = idx"
  51. >
  52. {{ item }}
  53. </div>
  54. </div>
  55. </div>
  56. <div class="filter-row">
  57. <span class="filter-label">品种:</span>
  58. <div class="filter-content tag-list">
  59. <div
  60. v-for="(item, idx) in varietyOptions"
  61. :key="`variety-${idx}`"
  62. class="filter-tag"
  63. :class="{ 'is-active': filters.varietyIndex === idx }"
  64. @click="filters.varietyIndex = idx"
  65. >
  66. {{ item }}
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. <div class="table-wrap">
  72. <el-table
  73. :data="tableData"
  74. border
  75. class="scheme-table"
  76. :header-cell-style="headerCellStyle"
  77. :cell-style="{ verticalAlign: 'top' }"
  78. >
  79. <el-table-column prop="name" label="农事名称" min-width="110" fixed />
  80. <el-table-column label="农事类型" min-width="120">
  81. <template #default="{ row }">
  82. <div class="type-tags">
  83. <span v-for="(item, idx) in row.types" :key="idx" class="type-tag">{{ item }}</span>
  84. </div>
  85. </template>
  86. </el-table-column>
  87. <el-table-column prop="trigger" label="触发条件" min-width="160" />
  88. <el-table-column label="药肥处方" min-width="260">
  89. <template #default="{ row }">
  90. <div class="prescription">
  91. <div class="prescription__title">{{ row.prescription.category }}</div>
  92. <div
  93. v-for="(line, idx) in row.prescription.lines"
  94. :key="idx"
  95. class="prescription__line"
  96. >
  97. {{ line }}
  98. </div>
  99. </div>
  100. </template>
  101. </el-table-column>
  102. <el-table-column label="执行规程" align="center">
  103. <el-table-column label="执行窗口" min-width="140" prop="execute.window" />
  104. <el-table-column label="执行设备" min-width="120">
  105. <template #default="{ row }">
  106. <div class="type-tags">
  107. <span
  108. v-for="(item, idx) in row.execute.devices"
  109. :key="idx"
  110. class="type-tag"
  111. >{{ item }}</span>
  112. </div>
  113. </template>
  114. </el-table-column>
  115. <el-table-column label="注意事项" min-width="160" prop="execute.notes" />
  116. </el-table-column>
  117. <el-table-column label="复核规程" align="center">
  118. <el-table-column label="复核时间" min-width="120">
  119. <template #default="{ row }">
  120. <span class="review-time">
  121. 执行后 <em class="review-time__num">{{ row.review.days }}</em> 天
  122. </span>
  123. </template>
  124. </el-table-column>
  125. <el-table-column label="复核标准" prop="review.standard" min-width="160" />
  126. </el-table-column>
  127. </el-table>
  128. </div>
  129. <div class="page-footer">
  130. <el-button type="warning" plain class="btn-copy" @click="onCopyScheme">
  131. 复制为我的方案
  132. </el-button>
  133. </div>
  134. </template>
  135. <!-- 我的方案 -->
  136. <MySchemePanel v-else @edit-scheme="onEditMyScheme" />
  137. </div>
  138. <EditSchemeDialog v-model="editDialogVisible" @confirm="onEditConfirm" />
  139. </div>
  140. </template>
  141. <script setup>
  142. import { reactive, ref } from "vue";
  143. import { ElMessage } from "element-plus";
  144. import EditSchemeDialog from "./components/EditSchemeDialog.vue";
  145. import MySchemePanel from "./components/MySchemePanel.vue";
  146. const tabs = [
  147. { label: "种植方案", value: "scheme" },
  148. { label: "我的方案", value: "mine" },
  149. ];
  150. const activeTab = ref("scheme");
  151. const editDialogVisible = ref(false);
  152. const filters = reactive({
  153. province: "",
  154. city: "",
  155. categoryIndex: 0,
  156. varietyIndex: 0,
  157. });
  158. const provinceOptions = [
  159. { label: "广东省", value: "guangdong" },
  160. { label: "广西壮族自治区", value: "guangxi" },
  161. { label: "海南省", value: "hainan" },
  162. ];
  163. const cityOptions = [
  164. { label: "广州市", value: "guangzhou" },
  165. { label: "深圳市", value: "shenzhen" },
  166. { label: "茂名市", value: "maoming" },
  167. ];
  168. const categoryOptions = ["荔枝", "水稻", "水稻", "水稻", "水稻", "水稻", "水稻"];
  169. const varietyOptions = ["妃子笑", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味", "桂味"];
  170. const placeholderText =
  171. "触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件触发条件";
  172. const tableData = ref([
  173. {
  174. name: "播前基肥",
  175. types: ["标准农事", "日常营养", "水肥类"],
  176. trigger: placeholderText,
  177. prescription: {
  178. category: "营养类",
  179. lines: [
  180. "砂土: 产品名称/用量/亩 使用次数",
  181. "粘土: 产品名称/用量/亩 使用次数",
  182. "壤土: 产品名称/用量/亩 使用次数",
  183. ],
  184. },
  185. execute: {
  186. window: "生育期起始-生育期结束",
  187. devices: ["农机设备一", "农机设备二", "农机设备三"],
  188. notes: placeholderText,
  189. },
  190. review: {
  191. days: 7,
  192. standard: placeholderText,
  193. },
  194. },
  195. {
  196. name: "播前基肥",
  197. types: ["标准农事", "日常营养", "水肥类"],
  198. trigger: placeholderText,
  199. prescription: {
  200. category: "营养类",
  201. lines: [
  202. "砂土: 产品名称/用量/亩 使用次数",
  203. "粘土: 产品名称/用量/亩 使用次数",
  204. "壤土: 产品名称/用量/亩 使用次数",
  205. ],
  206. },
  207. execute: {
  208. window: "生育期起始-生育期结束",
  209. devices: ["农机设备一", "农机设备二", "农机设备三"],
  210. notes: placeholderText,
  211. },
  212. review: {
  213. days: 7,
  214. standard: placeholderText,
  215. },
  216. },
  217. {
  218. name: "播前基肥",
  219. types: ["标准农事", "日常营养", "水肥类"],
  220. trigger: placeholderText,
  221. prescription: {
  222. category: "营养类",
  223. lines: [
  224. "砂土: 产品名称/用量/亩 使用次数",
  225. "粘土: 产品名称/用量/亩 使用次数",
  226. "壤土: 产品名称/用量/亩 使用次数",
  227. ],
  228. },
  229. execute: {
  230. window: "生育期起始-生育期结束",
  231. devices: ["农机设备一", "农机设备二", "农机设备三"],
  232. notes: placeholderText,
  233. },
  234. review: {
  235. days: 7,
  236. standard: placeholderText,
  237. },
  238. },
  239. ]);
  240. const headerCellStyle = {
  241. background: "#F5F5F5",
  242. color: "#535353",
  243. fontWeight: 400,
  244. };
  245. const onCopyScheme = () => {
  246. editDialogVisible.value = true;
  247. };
  248. const onEditMyScheme = () => {
  249. editDialogVisible.value = true;
  250. };
  251. const onEditConfirm = () => {
  252. ElMessage.success(activeTab.value === "mine" ? "方案已更新" : "已复制为我的方案");
  253. };
  254. </script>
  255. <style lang="scss" scoped>
  256. $primary: $warning-color;
  257. $primary-light: color.mix(#fff, $warning-color, 90%);
  258. $text: rgba(0, 0, 0, 0.6);
  259. $border: #e7e7e7;
  260. .planting-page {
  261. box-sizing: border-box;
  262. min-height: 100%;
  263. height: 100%;
  264. padding: 25px;
  265. display: flex;
  266. flex-direction: column;
  267. .page-card {
  268. flex: 1;
  269. min-height: 0;
  270. background: #fff;
  271. padding: 10px;
  272. display: flex;
  273. flex-direction: column;
  274. .page-header {
  275. display: flex;
  276. align-items: center;
  277. border-bottom: 1px solid $border;
  278. .page-tabs {
  279. display: flex;
  280. gap: 20px;
  281. &__item {
  282. position: relative;
  283. padding: 13px 16px;
  284. color: $text;
  285. cursor: pointer;
  286. &:hover {
  287. color: $primary;
  288. }
  289. &.is-active {
  290. color: $primary;
  291. &::after {
  292. content: "";
  293. position: absolute;
  294. left: 0;
  295. right: 0;
  296. bottom: -2px;
  297. height: 2px;
  298. background: $primary;
  299. border-radius: 2px 2px 0 0;
  300. }
  301. }
  302. }
  303. }
  304. }
  305. .filter-panel {
  306. padding: 20px 10px;
  307. display: flex;
  308. flex-direction: column;
  309. gap: 10px;
  310. .filter-row {
  311. display: flex;
  312. gap: 8px;
  313. .filter-label {
  314. line-height: 32px;
  315. color: $text;
  316. }
  317. .filter-content {
  318. &.region-selects {
  319. display: flex;
  320. gap: 8px;
  321. .region-select {
  322. width: 160px;
  323. }
  324. }
  325. &.tag-list {
  326. display: flex;
  327. flex-wrap: wrap;
  328. gap: 8px;
  329. .filter-tag {
  330. border: 1px solid transparent;
  331. background: #f3f3f3;
  332. color: $text;
  333. padding: 5px 10px;
  334. border-radius: 3px;
  335. cursor: pointer;
  336. &:hover {
  337. border-color: $primary;
  338. background: $primary-light;
  339. color: $primary;
  340. }
  341. &.is-active {
  342. background: $primary-light;
  343. border-color: $primary;
  344. color: $primary;
  345. }
  346. }
  347. }
  348. }
  349. }
  350. }
  351. .table-wrap {
  352. flex: 1;
  353. min-height: 0;
  354. overflow: auto;
  355. .scheme-table {
  356. color: #000;
  357. .type-tags {
  358. display: flex;
  359. flex-direction: column;
  360. align-items: flex-start;
  361. gap: 4px;
  362. .type-tag {
  363. padding: 1px 6px;
  364. border-radius: 4px;
  365. font-size: 12px;
  366. color: #2199f8;
  367. background: rgba(33, 153, 248, 0.1);
  368. }
  369. }
  370. .prescription {
  371. &__title {
  372. display: inline-block;
  373. width: fit-content;
  374. color: #4c4c4c;
  375. margin-bottom: 2px;
  376. background: rgba(125, 125, 125, 0.1);
  377. padding: 0 6px;
  378. border-radius: 2px;
  379. }
  380. &__line {
  381. font-size: 13px;
  382. }
  383. }
  384. .review-time {
  385. color: #000;
  386. font-style: normal;
  387. &__num {
  388. color: $primary;
  389. font-style: normal;
  390. font-weight: 500;
  391. }
  392. }
  393. }
  394. }
  395. .page-footer {
  396. flex-shrink: 0;
  397. display: flex;
  398. justify-content: flex-end;
  399. align-items: center;
  400. padding: 20px 10px 10px;
  401. .btn-copy {
  402. padding: 10px 16px;
  403. }
  404. }
  405. }
  406. }
  407. </style>