|
|
@@ -1,6 +1,6 @@
|
|
|
<template>
|
|
|
<div class="select-crop">
|
|
|
- <div class="select-crop__content" v-loading="loading">
|
|
|
+ <div class="select-crop__content" v-loading="loading" element-loading-background="rgba(15, 15, 15, 0.55)">
|
|
|
<div class="page-header">
|
|
|
<div class="page-title">请选择您的作物</div>
|
|
|
<div class="page-subtitle">已自动匹配您当地的主要作物</div>
|
|
|
@@ -16,6 +16,9 @@
|
|
|
@click="handleSelectCrop(item)"
|
|
|
>
|
|
|
{{ item.name }}
|
|
|
+ <span v-if="String(selectedCropId) === String(item.id)" class="chip-item__check">
|
|
|
+ <el-icon><Select /></el-icon>
|
|
|
+ </span>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -26,6 +29,7 @@
|
|
|
clearable
|
|
|
placeholder="搜索其他作物"
|
|
|
popper-class="entry-dark-select-popper"
|
|
|
+ @visible-change="handleCropSelectVisible"
|
|
|
@change="handleCropSearchSelect"
|
|
|
>
|
|
|
<template #prefix>
|
|
|
@@ -36,8 +40,9 @@
|
|
|
:key="item.id"
|
|
|
:label="item.name"
|
|
|
:value="String(item.id)"
|
|
|
- :disabled="!isCropAllowed(item)"
|
|
|
+ :class="{ 'is-disabled': !isCropAllowed(item) }"
|
|
|
/>
|
|
|
+ <!-- :disabled="!isCropAllowed(item)" -->
|
|
|
</el-select>
|
|
|
|
|
|
<!-- 品种 -->
|
|
|
@@ -46,7 +51,7 @@
|
|
|
<div class="section-title">{{ selectedCrop?.name || "" }}品种</div>
|
|
|
</div>
|
|
|
|
|
|
- <div class="chip-grid variety-grid" v-loading="varietyLoading">
|
|
|
+ <div class="chip-grid variety-grid" v-loading="varietyLoading" element-loading-background="rgba(15, 15, 15, 0.55)">
|
|
|
<div
|
|
|
v-for="item in displayVarieties"
|
|
|
:key="item.id"
|
|
|
@@ -56,7 +61,7 @@
|
|
|
>
|
|
|
<span class="chip-item__text">{{ item.name }}</span>
|
|
|
<span v-if="String(selectedVarietyId) === String(item.id)" class="chip-item__check">
|
|
|
- <el-icon><Check /></el-icon>
|
|
|
+ <el-icon><Select /></el-icon>
|
|
|
</span>
|
|
|
</div>
|
|
|
<div
|
|
|
@@ -75,6 +80,7 @@
|
|
|
placeholder="搜索其他品种"
|
|
|
:disabled="!selectedCropId"
|
|
|
popper-class="entry-dark-select-popper"
|
|
|
+ @visible-change="handleVarietySelectVisible"
|
|
|
@change="handleVarietySearchSelect"
|
|
|
>
|
|
|
<template #prefix>
|
|
|
@@ -92,17 +98,18 @@
|
|
|
|
|
|
<div class="select-crop__footer">
|
|
|
<div class="action-btn secondary" @click="emit('prev')">上一步</div>
|
|
|
- <div class="action-btn primary" @click="handleNext">
|
|
|
- {{ multiple ? "下一步" : "确认品种" }}
|
|
|
+ <div class="action-btn primary" :class="{ disabled: submitting }" @click="handleNext">
|
|
|
+ {{ primaryBtnText }}
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { computed, onMounted, ref } from "vue";
|
|
|
+import { computed, nextTick, onMounted, ref } from "vue";
|
|
|
import { ElMessage } from "element-plus";
|
|
|
import { Check, Search } from "@element-plus/icons-vue";
|
|
|
+import { selectNewlyCreatedFarm } from "@/utils/selectedFarm";
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
// Props / Emits
|
|
|
@@ -111,7 +118,7 @@ const props = defineProps({
|
|
|
/** 农服多选品类;农户为单选品类+品种 */
|
|
|
multiple: { type: Boolean, default: false },
|
|
|
});
|
|
|
-const emit = defineEmits(["prev", "next"]);
|
|
|
+const emit = defineEmits(["prev", "next", "complete"]);
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
// 常量
|
|
|
@@ -121,6 +128,14 @@ const VARIETY_LIST_KEY = "ENTRY_SELECTED_VARIETY_LIST";
|
|
|
const EQUIPMENT_KEY = "ENTRY_SELECTED_EQUIPMENT";
|
|
|
const TASK_KEY = "ENTRY_SELECTED_FARM_TASKS";
|
|
|
const LOCATION_KEY = "ENTRY_RESIDENT_LOCATION";
|
|
|
+const BA_FORM_KEY = "ENTRY_BA_FORM";
|
|
|
+const ADMIN_ID_KEY = "ENTRY_ADMIN_ID";
|
|
|
+const CROP_DETAIL_KEY = "ENTRY_CROP_DETAIL";
|
|
|
+const CROP_META_KEY = "ENTRY_CROP_META";
|
|
|
+const STEP_KEY = "ENTRY_INFORMATION_STEP";
|
|
|
+const INVITE_TYPE_KEY = "ENTRY_INVITE_TYPE";
|
|
|
+const MANUAL_VIEW_KEY = "ENTRY_MANUAL_VIEW";
|
|
|
+const EDIT_UID_KEY = "ENTRY_VARIETY_EDIT_UID";
|
|
|
const META_KEYS = new Set(["city", "county", "county_code", "province"]);
|
|
|
const FIRST_CROP_KEY_MAP = {
|
|
|
果树: "fruit",
|
|
|
@@ -130,14 +145,17 @@ const TAB_ORDER = ["果树", "大田"];
|
|
|
const DEFAULT_COUNTY_CODE = "440113";
|
|
|
const MAP_KEY = "CZLBZ-LJICQ-R4A5J-BN62X-YXCRJ-GNBUT";
|
|
|
const DEFAULT_POINT = "POINT(113.6142086995688 23.585836479509055)";
|
|
|
-/** 顶部默认展示的品类数量 */
|
|
|
-const DEFAULT_CROP_VISIBLE = 6;
|
|
|
+/** 品类 chip:1 行 × 3 列 */
|
|
|
+const DEFAULT_CROP_VISIBLE = 3;
|
|
|
+/** 品种 chip:3 行 × 2 列 */
|
|
|
+const DEFAULT_VARIETY_VISIBLE = 6;
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
// 页面状态
|
|
|
// ---------------------------------------------------------------------------
|
|
|
const loading = ref(false);
|
|
|
const varietyLoading = ref(false);
|
|
|
+const submitting = ref(false);
|
|
|
/** 全量品类(扁平) */
|
|
|
const allCrops = ref([]);
|
|
|
/** 顶部展示的品类(选中项会置顶) */
|
|
|
@@ -145,12 +163,20 @@ const displayCrops = ref([]);
|
|
|
const selectedCropId = ref("");
|
|
|
/** 农服多选 */
|
|
|
const selectedCropIds = ref(new Set());
|
|
|
+/** 仅「搜索其他作物」下拉选中后才有值,初始为空 */
|
|
|
const cropSearchValue = ref("");
|
|
|
+/** 打开下拉前备份,关闭未选新项时恢复 */
|
|
|
+let cropSearchBackup = "";
|
|
|
+/** 打开/恢复时改 v-model 会触发 change,用此标记忽略 */
|
|
|
+let cropSelectSilent = false;
|
|
|
|
|
|
const varietyList = ref([]);
|
|
|
const displayVarieties = ref([]);
|
|
|
const selectedVarietyId = ref("");
|
|
|
+/** 仅「搜索其他品种」下拉选中后才有值,初始为空 */
|
|
|
const varietySearchValue = ref("");
|
|
|
+let varietySearchBackup = "";
|
|
|
+let varietySelectSilent = false;
|
|
|
|
|
|
let varietyReqId = 0;
|
|
|
|
|
|
@@ -167,6 +193,12 @@ const cropSelectOptions = computed(() => allCrops.value);
|
|
|
|
|
|
const varietySelectOptions = computed(() => varietyList.value);
|
|
|
|
|
|
+const primaryBtnText = computed(() => {
|
|
|
+ if (props.multiple) return "下一步";
|
|
|
+ if (submitting.value) return "提交中...";
|
|
|
+ return "确认品种";
|
|
|
+});
|
|
|
+
|
|
|
const isCropSelected = (item) => {
|
|
|
if (!item) return false;
|
|
|
if (props.multiple) return selectedCropIds.value.has(String(item.id));
|
|
|
@@ -253,13 +285,35 @@ function promoteCropToFront(crop) {
|
|
|
if (!crop) return;
|
|
|
const id = String(crop.id);
|
|
|
const rest = displayCrops.value.filter((item) => String(item.id) !== id);
|
|
|
- displayCrops.value = [crop, ...rest];
|
|
|
+ displayCrops.value = [crop, ...rest].slice(0, DEFAULT_CROP_VISIBLE);
|
|
|
selectedCropId.value = crop.id;
|
|
|
if (props.multiple) {
|
|
|
selectedCropIds.value = new Set([id]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+function setCropSearchValueSilent(value) {
|
|
|
+ cropSelectSilent = true;
|
|
|
+ cropSearchValue.value = value;
|
|
|
+ nextTick(() => {
|
|
|
+ cropSelectSilent = false;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 打开:清空以便搜索;关闭未选新项:恢复打开前下拉自身的值(不回填 chip 默认选中)
|
|
|
+ */
|
|
|
+const handleCropSelectVisible = (visible) => {
|
|
|
+ if (visible) {
|
|
|
+ cropSearchBackup = cropSearchValue.value || "";
|
|
|
+ setCropSearchValueSilent("");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!cropSearchValue.value && cropSearchBackup) {
|
|
|
+ setCropSearchValueSilent(cropSearchBackup);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
function getResidentPoint() {
|
|
|
const saved = readJson(LOCATION_KEY);
|
|
|
return (
|
|
|
@@ -313,10 +367,30 @@ function promoteVarietyToFront(variety) {
|
|
|
if (!variety) return;
|
|
|
const id = String(variety.id);
|
|
|
const rest = displayVarieties.value.filter((item) => String(item.id) !== id);
|
|
|
- displayVarieties.value = [variety, ...rest];
|
|
|
+ displayVarieties.value = [variety, ...rest].slice(0, DEFAULT_VARIETY_VISIBLE);
|
|
|
selectedVarietyId.value = variety.id;
|
|
|
}
|
|
|
|
|
|
+function setVarietySearchValueSilent(value) {
|
|
|
+ varietySelectSilent = true;
|
|
|
+ varietySearchValue.value = value;
|
|
|
+ nextTick(() => {
|
|
|
+ varietySelectSilent = false;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/** 打开清空便于搜索;关闭未选新项:恢复打开前下拉自身的值 */
|
|
|
+const handleVarietySelectVisible = (visible) => {
|
|
|
+ if (visible) {
|
|
|
+ varietySearchBackup = varietySearchValue.value || "";
|
|
|
+ setVarietySearchValueSilent("");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!varietySearchValue.value && varietySearchBackup) {
|
|
|
+ setVarietySearchValueSilent(varietySearchBackup);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
function buildCategoryPayload(crop) {
|
|
|
return {
|
|
|
id: crop.id,
|
|
|
@@ -367,12 +441,14 @@ async function fetchVarietiesByCrop(cropId, { selectFirst = true } = {}) {
|
|
|
varietyList.value = [];
|
|
|
displayVarieties.value = [];
|
|
|
selectedVarietyId.value = "";
|
|
|
+ setVarietySearchValueSilent("");
|
|
|
return;
|
|
|
}
|
|
|
const reqId = ++varietyReqId;
|
|
|
varietyLoading.value = true;
|
|
|
try {
|
|
|
- const res = await VE_API.entry.getVarietiesByCrop({ crop_id: cropId });
|
|
|
+ // 品种 + crop_code 统一走 farmer_crop_detail
|
|
|
+ const res = await VE_API.entry.getMachines({ crop_id: cropId });
|
|
|
if (reqId !== varietyReqId) return;
|
|
|
if (res.code === 200 && res.data) {
|
|
|
const data = res.data;
|
|
|
@@ -381,18 +457,16 @@ async function fetchVarietiesByCrop(cropId, { selectFirst = true } = {}) {
|
|
|
crop.code = data.crop_code;
|
|
|
if (data.crop_group) crop.firstCrop = crop.firstCrop || data.crop_group;
|
|
|
}
|
|
|
- if (crop && data.crop_code) {
|
|
|
- saveCropDetailFromApi({
|
|
|
- crop_id: cropId,
|
|
|
- crop_code: data.crop_code,
|
|
|
- crop_group: data.crop_group || crop.firstCrop || "",
|
|
|
- crop_name: data.crop_name || crop.name,
|
|
|
- crop_type: data.crop_type || crop.groupName || "",
|
|
|
- });
|
|
|
- }
|
|
|
+ saveCropDetailFromApi({
|
|
|
+ crop_id: data.crop_id ?? cropId,
|
|
|
+ crop_code: data.crop_code || "",
|
|
|
+ crop_group: data.crop_group || crop?.firstCrop || "",
|
|
|
+ crop_name: data.crop_name || crop?.name || "",
|
|
|
+ crop_type: data.crop_type || crop?.groupName || "",
|
|
|
+ });
|
|
|
const list = mapVarieties(data.varieties);
|
|
|
varietyList.value = list;
|
|
|
- displayVarieties.value = [...list];
|
|
|
+ displayVarieties.value = list.slice(0, DEFAULT_VARIETY_VISIBLE);
|
|
|
|
|
|
const cached = readJson(VARIETY_LIST_KEY);
|
|
|
const cachedItem = Array.isArray(cached)
|
|
|
@@ -405,11 +479,13 @@ async function fetchVarietiesByCrop(cropId, { selectFirst = true } = {}) {
|
|
|
promoteVarietyToFront(list[0]);
|
|
|
} else {
|
|
|
selectedVarietyId.value = "";
|
|
|
+ setVarietySearchValueSilent("");
|
|
|
}
|
|
|
} else {
|
|
|
varietyList.value = [];
|
|
|
displayVarieties.value = [];
|
|
|
selectedVarietyId.value = "";
|
|
|
+ setVarietySearchValueSilent("");
|
|
|
ElMessage.error(res.msg || "获取品种列表失败");
|
|
|
}
|
|
|
} catch {
|
|
|
@@ -417,6 +493,7 @@ async function fetchVarietiesByCrop(cropId, { selectFirst = true } = {}) {
|
|
|
varietyList.value = [];
|
|
|
displayVarieties.value = [];
|
|
|
selectedVarietyId.value = "";
|
|
|
+ setVarietySearchValueSilent("");
|
|
|
ElMessage.error("获取品种列表失败,请稍后再试");
|
|
|
} finally {
|
|
|
if (reqId === varietyReqId) varietyLoading.value = false;
|
|
|
@@ -493,7 +570,7 @@ async function fetchCrops() {
|
|
|
|
|
|
const handleSelectCrop = async (item) => {
|
|
|
if (!isCropAllowed(item)) {
|
|
|
- ElMessage.warning("该品种暂未开放");
|
|
|
+ ElMessage.warning("该作物暂未开放");
|
|
|
return;
|
|
|
}
|
|
|
if (props.multiple) {
|
|
|
@@ -507,21 +584,32 @@ const handleSelectCrop = async (item) => {
|
|
|
}
|
|
|
if (String(selectedCropId.value) === String(item.id)) return;
|
|
|
selectedCropId.value = item.id;
|
|
|
- varietySearchValue.value = "";
|
|
|
+ // 点 chip 不写入搜索下拉;切换品类时清空品种搜索展示
|
|
|
+ setVarietySearchValueSilent("");
|
|
|
+ varietySearchBackup = "";
|
|
|
await fetchVarietiesByCrop(item.id, { selectFirst: true });
|
|
|
};
|
|
|
|
|
|
const handleCropSearchSelect = async (value) => {
|
|
|
+ if (cropSelectSilent) return;
|
|
|
if (value == null || value === "") return;
|
|
|
+
|
|
|
const crop = allCrops.value.find((item) => String(item.id) === String(value));
|
|
|
- cropSearchValue.value = "";
|
|
|
- if (!crop) return;
|
|
|
+ if (!crop) {
|
|
|
+ setCropSearchValueSilent(cropSearchBackup || "");
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (!isCropAllowed(crop)) {
|
|
|
+ setCropSearchValueSilent(cropSearchBackup || "");
|
|
|
ElMessage.warning("该品种暂未开放");
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
promoteCropToFront(crop);
|
|
|
- varietySearchValue.value = "";
|
|
|
+ cropSearchValue.value = String(crop.id);
|
|
|
+ cropSearchBackup = String(crop.id);
|
|
|
+ setVarietySearchValueSilent("");
|
|
|
+ varietySearchBackup = "";
|
|
|
if (!props.multiple) {
|
|
|
await fetchVarietiesByCrop(crop.id, { selectFirst: true });
|
|
|
}
|
|
|
@@ -533,14 +621,162 @@ const handleSelectVariety = (item) => {
|
|
|
};
|
|
|
|
|
|
const handleVarietySearchSelect = (value) => {
|
|
|
+ if (varietySelectSilent) return;
|
|
|
if (value == null || value === "") return;
|
|
|
const variety = varietyList.value.find((item) => String(item.id) === String(value));
|
|
|
- varietySearchValue.value = "";
|
|
|
- if (!variety) return;
|
|
|
+ if (!variety) {
|
|
|
+ setVarietySearchValueSilent(varietySearchBackup || "");
|
|
|
+ return;
|
|
|
+ }
|
|
|
promoteVarietyToFront(variety);
|
|
|
+ varietySearchValue.value = String(variety.id);
|
|
|
+ varietySearchBackup = String(variety.id);
|
|
|
};
|
|
|
|
|
|
-const handleNext = () => {
|
|
|
+function getUserId() {
|
|
|
+ const id = localStorage.getItem("MINI_USER_ID");
|
|
|
+ return id != null && id !== "" ? Number(id) : 0;
|
|
|
+}
|
|
|
+
|
|
|
+function getAdminId() {
|
|
|
+ const fromSession = sessionStorage.getItem(ADMIN_ID_KEY);
|
|
|
+ if (fromSession != null && fromSession !== "") return Number(fromSession);
|
|
|
+ return getUserId();
|
|
|
+}
|
|
|
+
|
|
|
+function getCropDetailMap() {
|
|
|
+ const cache = readJson(CROP_DETAIL_KEY);
|
|
|
+ return cache && typeof cache === "object" ? cache : {};
|
|
|
+}
|
|
|
+
|
|
|
+/** 农户确认品种后组装 addFarmInfo(不带设备) */
|
|
|
+function buildFarmPayload(crop, variety) {
|
|
|
+ const baForm = readJson(BA_FORM_KEY) || {};
|
|
|
+ const location = readJson(LOCATION_KEY);
|
|
|
+ const cropDetailMap = getCropDetailMap();
|
|
|
+ const detail = cropDetailMap[String(crop.id)] || {};
|
|
|
+ const farmLocation = location?.point || variety?.location || getResidentPoint();
|
|
|
+
|
|
|
+ return {
|
|
|
+ user_name: baForm.farmName || baForm.name,
|
|
|
+ tel: baForm.phone || "13000000000",
|
|
|
+ admin_id: getAdminId(),
|
|
|
+ user_id: getUserId(),
|
|
|
+ machine_id: [],
|
|
|
+ farm_location: farmLocation,
|
|
|
+ farm_address: location?.address || "",
|
|
|
+ crop_big_type: detail.crop_group || crop.firstCrop || "",
|
|
|
+ crops: [
|
|
|
+ {
|
|
|
+ crop_type: detail.crop_name || crop.name,
|
|
|
+ crop_code: detail.crop_code || crop.code || "",
|
|
|
+ crop_id: Number(crop.id),
|
|
|
+ variety_list: String(variety.varietyCode || variety.id),
|
|
|
+ phenophase_code: String(variety.phenophaseCode || variety.phenologyId || ""),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function buildCompleteMeta(crop, variety) {
|
|
|
+ const location = readJson(LOCATION_KEY) || {};
|
|
|
+ const meta = readJson(CROP_META_KEY) || {};
|
|
|
+ return {
|
|
|
+ locationLabel: location.address || meta.county || meta.city || "",
|
|
|
+ varietyLabel: variety?.name || "",
|
|
|
+ cropName: crop?.name || "",
|
|
|
+ farmName: (readJson(BA_FORM_KEY) || {}).farmName || "",
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function clearEntrySession() {
|
|
|
+ [
|
|
|
+ SESSION_KEY,
|
|
|
+ VARIETY_LIST_KEY,
|
|
|
+ EQUIPMENT_KEY,
|
|
|
+ TASK_KEY,
|
|
|
+ LOCATION_KEY,
|
|
|
+ BA_FORM_KEY,
|
|
|
+ ADMIN_ID_KEY,
|
|
|
+ CROP_DETAIL_KEY,
|
|
|
+ CROP_META_KEY,
|
|
|
+ STEP_KEY,
|
|
|
+ INVITE_TYPE_KEY,
|
|
|
+ MANUAL_VIEW_KEY,
|
|
|
+ EDIT_UID_KEY,
|
|
|
+ ].forEach((key) => sessionStorage.removeItem(key));
|
|
|
+}
|
|
|
+
|
|
|
+function pickFarmZoneIds(data) {
|
|
|
+ if (!data || typeof data !== "object") return null;
|
|
|
+ const farmId =
|
|
|
+ data.farm_id ?? data.farmId ?? data.farm?.farm_id ?? data.farm?.id ?? data.id;
|
|
|
+ const zoneId =
|
|
|
+ data.zone_id ??
|
|
|
+ data.zoneId ??
|
|
|
+ data.zone_ids?.[0] ??
|
|
|
+ data.zoneIds?.[0] ??
|
|
|
+ data.zone?.zone_id ??
|
|
|
+ data.zone?.id ??
|
|
|
+ data.default_zone_id ??
|
|
|
+ data.zones?.[0]?.zone_id ??
|
|
|
+ data.zones?.[0]?.id;
|
|
|
+ if (farmId == null || farmId === "" || zoneId == null || zoneId === "") return null;
|
|
|
+ return { farm_id: farmId, zone_id: zoneId };
|
|
|
+}
|
|
|
+
|
|
|
+function triggerReportApis(res, crop) {
|
|
|
+ const payload = res?.data && typeof res.data === "object" ? res.data : null;
|
|
|
+ const ids = pickFarmZoneIds(payload) || pickFarmZoneIds(res);
|
|
|
+ if (!ids) {
|
|
|
+ console.warn("generate_6module skipped: addFarmInfo 未返回 farm_id/zone_id", res);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const meta = readJson(CROP_META_KEY) || {};
|
|
|
+ VE_API.report
|
|
|
+ .generate6Module({
|
|
|
+ farm_id: ids.farm_id,
|
|
|
+ zone_id: ids.zone_id,
|
|
|
+ region: meta.city || meta.county || "",
|
|
|
+ crop: crop?.name || "",
|
|
|
+ })
|
|
|
+ .catch(() => {});
|
|
|
+}
|
|
|
+
|
|
|
+/** 农户:确认品种后直接提交建档 */
|
|
|
+async function submitFarmerEntry(crop, variety) {
|
|
|
+ if (submitting.value) return;
|
|
|
+ const baForm = readJson(BA_FORM_KEY);
|
|
|
+ if (!baForm?.farmName && !baForm?.name) {
|
|
|
+ ElMessage.warning("请先完善农场信息");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ submitting.value = true;
|
|
|
+ const completeMeta = buildCompleteMeta(crop, variety);
|
|
|
+ try {
|
|
|
+ const params = buildFarmPayload(crop, variety);
|
|
|
+ const raw = await VE_API.entry.addFarmInfo(params);
|
|
|
+ const res = Array.isArray(raw) ? raw[0] : raw;
|
|
|
+ if (res?.code === 200) {
|
|
|
+ triggerReportApis(res, crop);
|
|
|
+ await selectNewlyCreatedFarm();
|
|
|
+ clearEntrySession();
|
|
|
+ emit("complete", { archiveReady: true, ...completeMeta });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ElMessage.error(res?.msg || res?.message || "提交失败,请稍后再试");
|
|
|
+ } catch (error) {
|
|
|
+ console.error("entry submit failed", error);
|
|
|
+ ElMessage.error("提交失败");
|
|
|
+ } finally {
|
|
|
+ submitting.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleNext = async () => {
|
|
|
+ if (submitting.value) return;
|
|
|
+
|
|
|
if (props.multiple) {
|
|
|
const list = allCrops.value
|
|
|
.filter((item) => selectedCropIds.value.has(String(item.id)) && isCropAllowed(item))
|
|
|
@@ -577,7 +813,7 @@ const handleNext = () => {
|
|
|
|
|
|
writeJson(SESSION_KEY, [buildCategoryPayload(crop)]);
|
|
|
writeJson(VARIETY_LIST_KEY, [buildVarietyPayload(crop, variety)]);
|
|
|
- emit("next", { crop, variety });
|
|
|
+ await submitFarmerEntry(crop, variety);
|
|
|
};
|
|
|
|
|
|
onMounted(() => {
|
|
|
@@ -596,39 +832,38 @@ onMounted(() => {
|
|
|
color: #fff;
|
|
|
|
|
|
&__content {
|
|
|
- flex: 1;
|
|
|
min-height: 0;
|
|
|
overflow-y: auto;
|
|
|
- padding: 28px 16px 20px;
|
|
|
+ padding: 28px 24px 24px;
|
|
|
}
|
|
|
|
|
|
&__footer {
|
|
|
flex-shrink: 0;
|
|
|
display: flex;
|
|
|
gap: 12px;
|
|
|
- padding: 16px 16px calc(16px + env(safe-area-inset-bottom));
|
|
|
+ padding: 0 24px calc(16px + env(safe-area-inset-bottom));
|
|
|
}
|
|
|
|
|
|
.page-header {
|
|
|
margin-bottom: 18px;
|
|
|
|
|
|
.page-title {
|
|
|
- font-size: 24px;
|
|
|
- font-weight: 600;
|
|
|
- line-height: 34px;
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 30px;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
.page-subtitle {
|
|
|
- margin-top: 6px;
|
|
|
- font-size: 13px;
|
|
|
- line-height: 20px;
|
|
|
- color: rgba(255, 255, 255, 0.45);
|
|
|
+ margin-top: 2px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 21px;
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.section-header {
|
|
|
- margin: 22px 0 12px;
|
|
|
+ margin: 22px 0 10px;
|
|
|
|
|
|
.section-title {
|
|
|
font-size: 18px;
|
|
|
@@ -642,37 +877,45 @@ onMounted(() => {
|
|
|
display: grid;
|
|
|
gap: 10px;
|
|
|
margin-bottom: 12px;
|
|
|
+ overflow: hidden;
|
|
|
|
|
|
&.crop-grid {
|
|
|
grid-template-columns: repeat(3, 1fr);
|
|
|
+ /* 1 行:chip 65 + 不换行 */
|
|
|
+ max-height: 65px;
|
|
|
+ .chip-item {
|
|
|
+ height: 65px;
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
&.variety-grid {
|
|
|
grid-template-columns: repeat(2, 1fr);
|
|
|
min-height: 44px;
|
|
|
+ /* 3 行:44*3 + gap 10*2 */
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.chip-item {
|
|
|
position: relative;
|
|
|
- height: 44px;
|
|
|
- padding: 0 10px;
|
|
|
+ min-height: 55px;
|
|
|
+ padding: 0 10px 0 15px;
|
|
|
border-radius: 10px;
|
|
|
box-sizing: border-box;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
text-align: center;
|
|
|
- font-size: 15px;
|
|
|
- color: rgba(255, 255, 255, 0.85);
|
|
|
- background: #2a2a2a;
|
|
|
- border: 1px solid transparent;
|
|
|
+ font-size: 16px;
|
|
|
+ color: rgba(255, 255, 255, 1);
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.12);
|
|
|
cursor: pointer;
|
|
|
|
|
|
&.selected {
|
|
|
- color: #e8c56a;
|
|
|
- border-color: #e8c56a;
|
|
|
- background: rgba(232, 197, 106, 0.08);
|
|
|
+ color: rgba(255, 212, 137, 1);
|
|
|
+ border-color: rgba(255, 212, 137, 1);
|
|
|
+ background: rgba(255, 212, 137, 0.1);
|
|
|
}
|
|
|
|
|
|
&.variety-item {
|
|
|
@@ -688,26 +931,29 @@ onMounted(() => {
|
|
|
text-align: left;
|
|
|
}
|
|
|
|
|
|
- .chip-item__check {
|
|
|
- flex-shrink: 0;
|
|
|
- width: 20px;
|
|
|
- height: 20px;
|
|
|
- margin-left: 8px;
|
|
|
- border-radius: 50%;
|
|
|
- background: #e8c56a;
|
|
|
- color: #1a1a1a;
|
|
|
- display: inline-flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- font-size: 12px;
|
|
|
- }
|
|
|
-
|
|
|
&.selected {
|
|
|
justify-content: space-between;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ .chip-item__check {
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ margin-left: 10px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: rgba(255, 212, 137, 0.16);
|
|
|
+ border: 1px solid rgba(255, 212, 137, 1);
|
|
|
+ border-radius: 50%;
|
|
|
+ color: rgba(255, 212, 137, 1);
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
.empty-tip {
|
|
|
grid-column: 1 / -1;
|
|
|
padding: 24px 0;
|
|
|
@@ -718,7 +964,6 @@ onMounted(() => {
|
|
|
|
|
|
.search-select {
|
|
|
width: 100%;
|
|
|
- margin-bottom: 4px;
|
|
|
|
|
|
:deep(.el-select__wrapper) {
|
|
|
min-height: 44px;
|
|
|
@@ -774,6 +1019,11 @@ onMounted(() => {
|
|
|
background: linear-gradient(135deg, #f5e6b8 0%, #e8c56a 50%, #d4a84b 100%);
|
|
|
color: #1a1a1a;
|
|
|
}
|
|
|
+
|
|
|
+ &.disabled {
|
|
|
+ opacity: 0.55;
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
|
@@ -781,10 +1031,10 @@ onMounted(() => {
|
|
|
<style lang="scss">
|
|
|
.entry-dark-select-popper {
|
|
|
background: #1c1c1c !important;
|
|
|
- border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
|
|
+ border-color: rgba(255, 255, 255, 0.12) !important;
|
|
|
|
|
|
.el-select-dropdown__item {
|
|
|
- color: rgba(255, 255, 255, 0.85);
|
|
|
+ color: rgba(255, 255, 255, 0.9);
|
|
|
|
|
|
&.is-hovering,
|
|
|
&:hover {
|
|
|
@@ -795,6 +1045,11 @@ onMounted(() => {
|
|
|
color: #e8c56a;
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
+
|
|
|
+ &.is-disabled {
|
|
|
+ color: rgba(255, 255, 255, 0.5) !important;
|
|
|
+ cursor: not-allowed;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.el-popper__arrow::before {
|