| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155 |
- <template>
- <div class="select-variety">
- <div class="select-variety__content">
- <div class="page-header">
- <div class="page-title">请选择您的种植品种</div>
- <div class="page-subtitle">请确定您的果园设施以及内容</div>
- </div>
- <!-- 品类 Tab + 品种选择,照常显示 -->
- <div class="category-tabs" v-if="categoryTabs.length">
- <div
- v-for="(tab, index) in categoryTabs"
- :key="tab.id"
- class="category-tab"
- :class="{
- active: activeCategoryId === tab.id,
- first: index % 3 === 0,
- last: index === categoryTabs.length - 1,
- }"
- @click="activeCategoryId = tab.id"
- >
- <span>{{ tab.name }}</span>
- </div>
- </div>
- <div class="variety-card" v-loading="varietyLoading">
- <el-input v-model="searchKeyword" class="search-bar" placeholder="请输入品种" @keyup.enter="handleSearch">
- <template #prefix>
- <el-icon class="search-icon">
- <Search />
- </el-icon>
- </template>
- <template #suffix>
- <span class="search-btn" @click="handleSearch">搜索</span>
- </template>
- </el-input>
- <div class="variety-grid">
- <div v-for="item in visibleVarieties" :key="item.id" class="variety-item"
- :class="{ selected: isSelected(item.id) }" @click="toggleVariety(item)">
- {{ item.name }}
- </div>
- </div>
- <div v-if="!varietyLoading && !filteredVarieties.length" class="empty-tip">暂无品种</div>
- <div v-if="filteredVarieties.length > DEFAULT_VISIBLE_COUNT" class="expand-trigger"
- @click="gridExpanded = !gridExpanded">
- {{ gridExpanded ? "点击收起" : "点击展开更多" }}
- </div>
- </div>
- <!-- 默认表单卡:始终在已选卡片上方 -->
- <div class="form-card form-card--default">
- <div class="form-card__header">
- <img class="title-icon" src="@/assets/img/home/label-icon.png" alt="" />
- <el-select v-model="defaultForm.varietyId" class="variety-select" placeholder="选择品种"
- popper-class="variety-select-popper"
- @change="handleDefaultVarietyChange">
- <el-option v-for="item in allVarieties" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </div>
- <div class="form-card__body form-card__body--locked" @click="tipSelectVariety">
- <div class="form-row">
- <span class="form-label">当下物候期</span>
- <el-select
- v-model="defaultForm.phenologyId"
- class="form-select"
- placeholder="选择物候期"
- placement="bottom-end"
- popper-class="variety-select-popper"
- >
- <el-option
- v-for="opt in currentPhenologyOptions"
- :key="opt.id"
- :label="opt.name"
- :value="opt.id"
- />
- </el-select>
- </div>
- <div class="form-row">
- <span class="form-label muted">{{ currentStartingPointQuestion }}</span>
- <el-date-picker
- v-model="defaultForm.startTime"
- class="form-picker"
- type="date"
- placeholder="请选择时间"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- :clearable="false"
- style="width: 130px"
- readonly
- />
- </div>
- <div class="form-row">
- <span class="form-label">种植亩数</span>
- <el-input
- v-model.number="defaultForm.area"
- class="form-input"
- placeholder="请输入亩数"
- type="number"
- />
- </div>
- <div class="form-row location-row">
- <span class="form-label">选择种植点位</span>
- <div class="map" ref="defaultMapRef"></div>
- </div>
- </div>
- </div>
- <!-- 已选品种详情卡 -->
- <div v-for="(item, index) in selectedList" :key="item.uid" class="form-card selected-card">
- <div class="form-card__header">
- <img class="title-icon" src="@/assets/img/home/label-icon.png" alt="" />
- <el-select v-model="item.id" class="variety-select" placeholder="选择品种"
- popper-class="variety-select-popper"
- @change="(val) => handleSelectedVarietyChange(index, val)">
- <el-option v-for="opt in allVarieties" :key="opt.id" :label="opt.name" :value="opt.id" />
- </el-select>
- <span class="delete-btn" @click="removeVariety(item.uid)">删除</span>
- </div>
- <div class="form-card__body">
- <div class="form-row">
- <span class="form-label">当下物候期</span>
- <el-select
- v-model="item.phenologyId"
- class="form-select"
- placeholder="选择物候期"
- placement="bottom-end"
- popper-class="variety-select-popper"
- >
- <el-option
- v-for="opt in getPhenologyOptions(item.categoryId)"
- :key="opt.id"
- :label="opt.name"
- :value="opt.id"
- />
- </el-select>
- </div>
- <div class="form-row">
- <span class="form-label">{{ getStartingPointQuestion(item.categoryId) }}</span>
- <el-date-picker
- v-model="item.startTime"
- class="form-picker"
- type="date"
- placeholder="请选择时间"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- :clearable="false"
- style="width: 130px"
- />
- </div>
- <div class="form-row">
- <span class="form-label">种植亩数</span>
- <el-input v-model="item.area" class="form-input" placeholder="请输入亩数" type="number" />
- </div>
- <div class="form-row location-row">
- <span class="form-label">选择种植点位</span>
- <div
- class="map map--clickable"
- :ref="(el) => setItemMapRef(item.uid, el)"
- @click="goSelectItemLocation(item)"
- ></div>
- </div>
- </div>
- </div>
- </div>
- <div class="custom-bottom-fixed-btns">
- <div class="bottom-btn secondary-btn" @click="handlePrev">上一步</div>
- <div class="bottom-btn primary-btn" :class="{ disabled: submitting }" @click="handleConfirm">
- {{ submitting ? "提交中..." : "确定信息" }}
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { computed, nextTick, onActivated, onBeforeUnmount, onMounted, reactive, ref, watch } from "vue";
- import { ElMessage } from "element-plus";
- import { Search } from "@element-plus/icons-vue";
- import { useRouter } from "vue-router";
- import { useStore } from "vuex";
- import SelectLocationMap from "../map/selectLocationMap.js";
- const emit = defineEmits(["prev", "confirm"]);
- const router = useRouter();
- const store = useStore();
- const DEFAULT_VISIBLE_COUNT = 8;
- const DEFAULT_POINT = "POINT(113.6142086995688 23.585836479509055)";
- const LOCATION_KEY = "ENTRY_RESIDENT_LOCATION";
- const EDIT_UID_KEY = "ENTRY_VARIETY_EDIT_UID";
- const SELECTED_LIST_KEY = "ENTRY_SELECTED_VARIETY_LIST";
- const CATEGORY_SESSION_KEY = "ENTRY_SELECTED_CATEGORY";
- const MAP_PADDING = [6, 6, 6, 6];
- let selectedUid = 0;
- const defaultMapRef = ref(null);
- let defaultPreviewMap = null;
- const itemPreviewMaps = new Map();
- function getDefaultPoint() {
- return (
- localStorage.getItem("MINI_USER_LOCATION_POINT") ||
- store.state.home.miniUserLocationPoint ||
- DEFAULT_POINT
- );
- }
- function utilWktToCoordinate(point) {
- const match = String(point).match(/POINT\s*\(([\d.\-]+)\s+([\d.\-]+)\)/i);
- if (!match) return null;
- return [Number(match[1]), Number(match[2])];
- }
- function createPreviewMap(el, point, showPoint = false) {
- if (!el || !point) return null;
- const map = new SelectLocationMap();
- map.initMap(point, el, {
- enableClick: false,
- padding: MAP_PADDING,
- showPoint,
- });
- nextTick(() => {
- map.kmap?.map?.updateSize?.();
- });
- return map;
- }
- function destroyPreviewMap(map) {
- map?.clearLayer();
- }
- function updateItemMap(uid, point, showPoint) {
- const map = itemPreviewMaps.get(uid);
- if (!map?.kmap || !point) return;
- const coordinate = utilWktToCoordinate(point);
- if (!coordinate) return;
- if (showPoint) {
- map.showPoint(coordinate);
- } else {
- map.hidePoint();
- map.setMapPosition(coordinate, false);
- }
- }
- function setItemMapRef(uid, el) {
- if (!el) {
- destroyPreviewMap(itemPreviewMaps.get(uid));
- itemPreviewMaps.delete(uid);
- return;
- }
- if (itemPreviewMaps.has(uid)) {
- nextTick(() => itemPreviewMaps.get(uid)?.kmap?.map?.updateSize?.());
- return;
- }
- nextTick(() => {
- const item = selectedList.value.find((i) => i.uid === uid);
- const point = item?.location || getDefaultPoint();
- const map = createPreviewMap(el, point, !!item?.location);
- if (map) itemPreviewMaps.set(uid, map);
- });
- }
- function initDefaultMap() {
- if (!defaultMapRef.value) return;
- if (defaultPreviewMap) {
- nextTick(() => defaultPreviewMap.kmap?.map?.updateSize?.());
- return;
- }
- defaultPreviewMap = createPreviewMap(defaultMapRef.value, getDefaultPoint(), false);
- }
- function syncItemLocationFromSession() {
- const uid = sessionStorage.getItem(EDIT_UID_KEY);
- if (!uid) return;
- sessionStorage.removeItem(EDIT_UID_KEY);
- try {
- const raw = sessionStorage.getItem(LOCATION_KEY);
- const saved = raw ? JSON.parse(raw) : null;
- if (!saved?.point) return;
- const item = selectedList.value.find((i) => i.uid === uid);
- if (!item) return;
- item.location = saved.point;
- saveSelectedListDraft();
- nextTick(() => updateItemMap(uid, saved.point, true));
- } catch {
- // ignore
- }
- }
- function saveSelectedListDraft() {
- try {
- sessionStorage.setItem(
- SELECTED_LIST_KEY,
- JSON.stringify({
- selectedUid,
- activeCategoryId: activeCategoryId.value,
- list: selectedList.value,
- })
- );
- } catch {
- // ignore
- }
- }
- function restoreSelectedListDraft() {
- try {
- const raw = sessionStorage.getItem(SELECTED_LIST_KEY);
- if (!raw) return;
- const draft = JSON.parse(raw);
- if (draft?.activeCategoryId != null) {
- activeCategoryId.value = draft.activeCategoryId;
- }
- if (typeof draft?.selectedUid === "number") {
- selectedUid = draft.selectedUid;
- }
- if (Array.isArray(draft?.list)) {
- selectedList.value = draft.list;
- }
- } catch {
- // ignore
- }
- }
- const goSelectItemLocation = (item) => {
- sessionStorage.setItem(EDIT_UID_KEY, item.uid);
- saveSelectedListDraft();
- router.push({
- path: "/entry_select_location",
- query: { mapCenter: item.location || getDefaultPoint() },
- });
- };
- onMounted(async () => {
- initCategoryTabsFromSession();
- restoreSelectedListDraft();
- syncItemLocationFromSession();
- nextTick(() => initDefaultMap());
- await Promise.all(
- categoryTabs.value.map((tab) => fetchVarietiesByCrop(tab.id))
- );
- });
- onActivated(async () => {
- initCategoryTabsFromSession();
- restoreSelectedListDraft();
- syncItemLocationFromSession();
- nextTick(() => {
- initDefaultMap();
- itemPreviewMaps.forEach((map) => map.kmap?.map?.updateSize?.());
- });
- await Promise.all(
- categoryTabs.value.map((tab) => fetchVarietiesByCrop(tab.id))
- );
- });
- onBeforeUnmount(() => {
- destroyPreviewMap(defaultPreviewMap);
- defaultPreviewMap = null;
- itemPreviewMaps.forEach((map) => destroyPreviewMap(map));
- itemPreviewMaps.clear();
- });
- const getSelectedCategoriesFromSession = () => {
- try {
- const raw = sessionStorage.getItem(CATEGORY_SESSION_KEY);
- if (!raw) return [];
- const list = JSON.parse(raw);
- return Array.isArray(list) ? list : [];
- } catch {
- return [];
- }
- };
- const mapPhenologyList = (list) => {
- if (!Array.isArray(list)) return [];
- return list
- .map((item, index) => {
- if (typeof item === "string") {
- return { id: item, name: item };
- }
- const name = item?.name || item?.phenology || String(item?.id ?? index);
- const id = item?.id ?? name;
- return { id, name };
- })
- .filter((item) => item.name);
- };
- const initCategoryTabsFromSession = () => {
- const selected = getSelectedCategoriesFromSession();
- const prevLoaded = new Map(
- categoryTabs.value.map((tab) => [String(tab.id), tab])
- );
- categoryTabs.value = selected.map((item) => {
- const id = item.id;
- const cached = prevLoaded.get(String(id));
- if (cached?.loaded) {
- return {
- ...cached,
- name: item.name || cached.name,
- };
- }
- return {
- id,
- name: item.name || "",
- varieties: [],
- phenology: [],
- startingPointQuestion: "起种点问题",
- loaded: false,
- };
- });
- if (!categoryTabs.value.length) {
- activeCategoryId.value = null;
- return;
- }
- const stillExists = categoryTabs.value.some(
- (tab) => String(tab.id) === String(activeCategoryId.value)
- );
- if (!stillExists) {
- activeCategoryId.value = categoryTabs.value[0].id;
- }
- };
- const categoryTabs = ref([]);
- const activeCategoryId = ref(null);
- const varietyLoading = ref(false);
- const searchKeyword = ref("");
- const appliedKeyword = ref("");
- const gridExpanded = ref(false);
- const selectedList = ref([]);
- const defaultForm = reactive({
- varietyId: "",
- varietyName: "",
- phenologyId: "",
- startTime: "",
- area: "",
- });
- const fetchVarietiesByCrop = async (cropId, force = false) => {
- if (cropId == null || cropId === "") return;
- const tab = categoryTabs.value.find((item) => String(item.id) === String(cropId));
- if (!tab) return;
- if (tab.loaded && !force) return;
- const showLoading = String(cropId) === String(activeCategoryId.value);
- if (showLoading) varietyLoading.value = true;
- try {
- const res = await VE_API.entry.getVarietiesByCrop({
- crop_id: cropId,
- });
- if (res.code === 200 && res.data) {
- const data = res.data;
- tab.varieties = (data.varieties || []).map((item) => ({
- id: item.id,
- name: item.name,
- }));
- tab.phenology = mapPhenologyList(data.phenology);
- tab.startingPointQuestion =
- data.starting_point_question || "起种点问题";
- tab.loaded = true;
- } else {
- tab.varieties = [];
- tab.phenology = [];
- tab.startingPointQuestion = "起种点问题";
- if (showLoading) {
- ElMessage.error(res.msg || "获取品种列表失败");
- }
- }
- } catch {
- tab.varieties = [];
- tab.phenology = [];
- tab.startingPointQuestion = "起种点问题";
- if (showLoading) {
- ElMessage.error("获取品种列表失败,请稍后再试");
- }
- } finally {
- if (showLoading) varietyLoading.value = false;
- }
- };
- watch(
- selectedList,
- () => {
- saveSelectedListDraft();
- },
- { deep: true }
- );
- const currentCategory = computed(
- () =>
- categoryTabs.value.find((tab) => String(tab.id) === String(activeCategoryId.value)) ||
- categoryTabs.value[0]
- );
- const getPhenologyOptions = (categoryId) => {
- const tab = categoryTabs.value.find((item) => String(item.id) === String(categoryId));
- return tab?.phenology || [];
- };
- const getStartingPointQuestion = (categoryId) => {
- const tab = categoryTabs.value.find((item) => String(item.id) === String(categoryId));
- return tab?.startingPointQuestion || "起种点问题";
- };
- const currentPhenologyOptions = computed(() => getPhenologyOptions(activeCategoryId.value));
- const currentStartingPointQuestion = computed(() =>
- getStartingPointQuestion(activeCategoryId.value)
- );
- const allVarieties = computed(() => {
- const list = [];
- for (const tab of categoryTabs.value) {
- for (const item of tab.varieties || []) {
- list.push({
- ...item,
- categoryId: tab.id,
- categoryName: tab.name,
- });
- }
- }
- return list;
- });
- const filteredVarieties = computed(() => {
- const list = currentCategory.value?.varieties || [];
- const kw = appliedKeyword.value.trim();
- if (!kw) return list;
- return list.filter((item) => item.name.includes(kw));
- });
- const visibleVarieties = computed(() => {
- if (gridExpanded.value) return filteredVarieties.value;
- return filteredVarieties.value.slice(0, DEFAULT_VISIBLE_COUNT);
- });
- watch(activeCategoryId, (id) => {
- searchKeyword.value = "";
- appliedKeyword.value = "";
- gridExpanded.value = false;
- resetDefaultForm();
- if (id != null) {
- fetchVarietiesByCrop(id);
- }
- });
- const isSelected = (id) =>
- selectedList.value.some((item) => String(item.id) === String(id));
- const handleSearch = () => {
- appliedKeyword.value = searchKeyword.value;
- gridExpanded.value = false;
- };
- const createSelectedItem = (variety, category) => ({
- uid: `sel-${++selectedUid}`,
- id: variety.id,
- name: variety.name,
- categoryId: category.id,
- categoryName: category.name,
- phenologyId: "",
- startTime: "",
- area: "",
- location: "",
- });
- const resetDefaultForm = () => {
- defaultForm.varietyId = "";
- defaultForm.varietyName = "";
- defaultForm.phenologyId = "";
- defaultForm.startTime = "";
- defaultForm.area = "";
- };
- const tipSelectVariety = () => {
- ElMessage.warning("请选择品种");
- };
- /** 顶部「选择品种」:选中后新增下方卡片,顶部表单重置为空 */
- const handleDefaultVarietyChange = (varietyId) => {
- if (!varietyId) return;
- const found = allVarieties.value.find((item) => String(item.id) === String(varietyId));
- if (!found) {
- resetDefaultForm();
- return;
- }
- if (!isSelected(found.id)) {
- selectedList.value.unshift(
- createSelectedItem(found, {
- id: found.categoryId,
- name: found.categoryName,
- })
- );
- saveSelectedListDraft();
- }
- nextTick(() => {
- resetDefaultForm();
- });
- };
- const handleSelectedVarietyChange = (index, varietyId) => {
- const found = allVarieties.value.find((item) => String(item.id) === String(varietyId));
- const item = selectedList.value[index];
- if (!item || !found) return;
- item.id = found.id;
- item.name = found.name;
- item.categoryId = found.categoryId;
- item.categoryName = found.categoryName;
- item.phenologyId = "";
- saveSelectedListDraft();
- };
- const toggleVariety = (variety) => {
- const index = selectedList.value.findIndex((item) => String(item.id) === String(variety.id));
- if (index > -1) {
- selectedList.value.splice(index, 1);
- saveSelectedListDraft();
- return;
- }
- selectedList.value.unshift(createSelectedItem(variety, currentCategory.value));
- saveSelectedListDraft();
- };
- const removeVariety = (uid) => {
- const index = selectedList.value.findIndex((item) => item.uid === uid);
- if (index > -1) {
- selectedList.value.splice(index, 1);
- saveSelectedListDraft();
- }
- };
- const handlePrev = () => {
- const idx = categoryTabs.value.findIndex(
- (tab) => String(tab.id) === String(activeCategoryId.value)
- );
- if (idx > 0) {
- activeCategoryId.value = categoryTabs.value[idx - 1].id;
- saveSelectedListDraft();
- return;
- }
- emit("prev");
- };
- const getBaForm = () => {
- try {
- const raw = sessionStorage.getItem("ENTRY_BA_FORM");
- return raw ? JSON.parse(raw) : null;
- } catch {
- return null;
- }
- };
- const getPhenophaseLabel = (item) => {
- const options = getPhenologyOptions(item.categoryId);
- const found = options.find((opt) => String(opt.id) === String(item.phenologyId));
- return found?.name || String(item.phenologyId || "");
- };
- const validateSubmitData = () => {
- if (!categoryTabs.value.length) {
- ElMessage.warning("请先选择种植品类");
- return false;
- }
- if (!selectedList.value.length) {
- ElMessage.warning("请至少选择一个品种");
- return false;
- }
- for (const tab of categoryTabs.value) {
- const hasVariety = selectedList.value.some(
- (item) => String(item.categoryId) === String(tab.id)
- );
- if (!hasVariety) {
- ElMessage.warning(`请为「${tab.name}」选择品种并填写信息`);
- activeCategoryId.value = tab.id;
- return false;
- }
- }
- for (const item of selectedList.value) {
- if (!item.phenologyId) {
- ElMessage.warning(`请选择「${item.name}」的当下物候期`);
- return false;
- }
- if (!item.startTime) {
- ElMessage.warning(`请填写「${item.name}」的起种点时间`);
- return false;
- }
- if (item.area === "" || item.area == null || Number(item.area) <= 0) {
- ElMessage.warning(`请填写「${item.name}」的种植亩数`);
- return false;
- }
- if (!item.location) {
- ElMessage.warning(`请选择「${item.name}」的种植点位`);
- return false;
- }
- }
- const baForm = getBaForm();
- if (!baForm?.name || !baForm?.phone) {
- ElMessage.warning("请先完善个人信息");
- return false;
- }
- return true;
- };
- const buildPlotPayload = () => {
- const baForm = getBaForm() || {};
- return {
- user_name: baForm.name,
- tel: baForm.phone,
- crops: selectedList.value.map((item) => ({
- crop_type: item.categoryName,
- crop_id: Number(item.categoryId),
- variety_list: [Number(item.id)],
- phenophase: getPhenophaseLabel(item),
- start_time: item.startTime,
- plant_area: Number(item.area),
- point: item.location,
- })),
- };
- };
- const clearEntrySession = () => {
- sessionStorage.removeItem(SELECTED_LIST_KEY);
- sessionStorage.removeItem(CATEGORY_SESSION_KEY);
- sessionStorage.removeItem("ENTRY_BA_FORM");
- sessionStorage.removeItem(LOCATION_KEY);
- sessionStorage.removeItem(EDIT_UID_KEY);
- };
- const submitting = ref(false);
- const handleConfirm = async () => {
- const idx = categoryTabs.value.findIndex(
- (tab) => String(tab.id) === String(activeCategoryId.value)
- );
- if (idx > -1 && idx < categoryTabs.value.length - 1) {
- activeCategoryId.value = categoryTabs.value[idx + 1].id;
- saveSelectedListDraft();
- return;
- }
- if (!validateSubmitData()) return;
- if (submitting.value) return;
- submitting.value = true;
- try {
- const params = buildPlotPayload();
- console.log('params', params);
- // const res = await VE_API.entry.addPlotInfo(params);
- // if (res.code === 200) {
- // ElMessage.success(res.msg || "提交成功");
- // clearEntrySession();
- // emit("confirm", params);
- // } else {
- // ElMessage.error(res.msg || "提交失败,请稍后再试");
- // }
- } catch {
- ElMessage.error("提交失败,请稍后再试");
- } finally {
- submitting.value = false;
- }
- };
- </script>
- <style lang="scss" scoped>
- .select-variety {
- flex: 1;
- min-height: 0;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- &__content {
- flex: 1;
- min-height: 0;
- overflow-y: auto;
- -webkit-overflow-scrolling: touch;
- padding: 20px 10px 100px;
- .page-header {
- margin-bottom: 20px;
- .page-title {
- font-size: 26px;
- color: #005599;
- font-family: "PangMenZhengDao";
- }
- .page-subtitle {
- color: rgba(46, 46, 46, 0.4);
- }
- }
- .category-tabs {
- display: flex;
- flex-wrap: wrap;
- row-gap: 8px;
- margin-bottom: 10px;
- .category-tab {
- --arrow: 20px;
- flex: 0 0 calc((100% + 16px) / 3);
- height: 30px;
- display: flex;
- align-items: center;
- justify-content: center;
- color: #4e5969;
- background: #e8f3ff;
- cursor: default;
- pointer-events: none;
- clip-path: polygon(0 0,
- calc(100% - var(--arrow)) 0,
- 100% 50%,
- calc(100% - var(--arrow)) 100%,
- 0 100%,
- var(--arrow) 50%);
- margin-left: -8px;
- &.first {
- margin-left: 0;
- clip-path: polygon(0 0,
- calc(100% - var(--arrow)) 0,
- 100% 50%,
- calc(100% - var(--arrow)) 100%,
- 0 100%);
- }
- &.last {
- clip-path: polygon(0 0,
- 100% 0,
- 100% 100%,
- 0 100%,
- var(--arrow) 50%);
- }
- &.active {
- color: #fff;
- background: #2199f8;
- }
- }
- }
- .variety-card {
- margin-bottom: 10px;
- background: rgba(255, 255, 255, 0.5);
- border: 1px solid #fff;
- border-radius: 10px;
- padding: 10px 6px;
- .search-bar {
- margin-bottom: 10px;
- :deep(.el-input__wrapper) {
- height: 36px;
- padding: 0 10px;
- background: #fff;
- border-radius: 6px;
- box-shadow: none;
- }
- :deep(.el-input__inner) {
- color: #1a1a1a;
- line-height: 20px;
- &::placeholder {
- color: rgba(29, 33, 41, 0.2);
- }
- }
- .search-icon {
- font-size: 16px;
- color: rgba(0, 0, 0, 0.2);
- }
- .search-btn {
- color: #2199f8;
- }
- }
- .variety-grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 8px;
- .variety-item {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 7px 0;
- background: #fff;
- border: 1px solid transparent;
- border-radius: 6px;
- color: #565656;
- text-align: center;
- &.selected {
- color: #2199f8;
- background: rgba(33, 153, 248, 0.1);
- border-color: #2199f8;
- }
- }
- }
- .expand-trigger {
- margin-top: 10px;
- text-align: center;
- color: rgba(0, 0, 0, 0.6);
- }
- .empty-tip {
- padding: 24px 0 10px;
- text-align: center;
- color: rgba(0, 0, 0, 0.35);
- font-size: 14px;
- }
- }
- .form-card {
- margin-bottom: 10px;
- background: #fff;
- border-radius: 10px;
- padding: 12px;
- &__header {
- display: flex;
- align-items: center;
- border-bottom: .2px solid rgba(0, 0, 0, 0.05);
- padding-bottom: 10px;
- .title-icon {
- width: 15px;
- object-fit: contain;
- margin-right: 5px;
- }
- .variety-select {
- flex: 0 0 auto;
- width: auto !important;
- max-width: calc(100% - 50px);
- :deep(.el-select__wrapper) {
- box-shadow: none;
- padding: 0;
- display: inline-flex;
- width: auto !important;
- }
- :deep(.el-select__selection) {
- display: inline-flex;
- width: auto;
- flex: 0 0 auto;
- }
- :deep(.el-select__placeholder) {
- position: static;
- font-size: 16px;
- color: #000;
- transform: none;
- }
- :deep(.el-select__caret) {
- color: #000;
- font-size: 16px;
- }
- }
- .delete-btn {
- flex-shrink: 0;
- margin-left: auto;
- padding-left: 12px;
- font-size: 14px;
- color: #f53f3f;
- line-height: 20px;
- white-space: nowrap;
- }
- }
- &--default {
- .form-card__header {
- .variety-select {
- :deep(.el-select__selected-item),
- :deep(.el-select__placeholder) {
- color: #1D2129;
- }
- :deep(.el-select__placeholder.is-transparent) {
- color: rgba(34, 34, 34, 0.3);
- }
- :deep(.el-select__caret) {
- color: rgba(34, 34, 34, 0.3);
- }
- }
- }
- .form-card__body--locked {
- cursor: pointer;
- .form-row {
- pointer-events: none;
- }
- }
- }
- .form-row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
- margin-top: 10px;
- .form-label {
- font-size: 14px;
- color: #1D2129;
- &.muted {
- color: rgba(29, 33, 41, 0.2);
- }
- }
- .form-input {
- flex: 1;
- min-width: 0;
- :deep(.el-input__wrapper) {
- box-shadow: none;
- background: transparent;
- padding: 0;
- justify-content: flex-end;
- }
- :deep(.el-input__inner) {
- text-align: right;
- font-size: 14px;
- color: #1a1a1a;
- &::placeholder {
- color: rgba(0, 0, 0, 0.25);
- }
- }
- }
- .form-select {
- flex: 0 0 auto;
- width: auto;
- max-width: 160px;
- margin-left: auto;
- :deep(.el-select__wrapper) {
- box-shadow: none;
- background: transparent;
- padding: 0;
- justify-content: flex-end;
- min-height: auto;
- width: auto;
- }
- :deep(.el-select__selection) {
- justify-content: flex-end;
- flex: 0 1 auto;
- }
- :deep(.el-select__placeholder),
- :deep(.el-select__selected-item) {
- text-align: right;
- font-size: 14px;
- color: #1a1a1a;
- }
- :deep(.el-select__placeholder) {
- color: #1D2129;
- position: static;
- transform: none;
- }
- :deep(.el-select__placeholder.is-transparent) {
- color: rgba(0, 0, 0, 0.25);
- }
- :deep(.el-select__caret) {
- color: rgba(0, 0, 0, 0.25);
- }
- }
- .map {
- width: 98px;
- height: 60px;
- flex-shrink: 0;
- margin-left: auto;
- border-radius: 8px;
- overflow: hidden;
- background: linear-gradient(135deg, #e8eef3 0%, #d4dde6 100%);
- pointer-events: none;
- &--clickable {
- pointer-events: auto;
- cursor: pointer;
- }
- }
- }
- }
- }
- .custom-bottom-fixed-btns {
- display: flex;
- justify-content: space-between;
- align-items: baseline;
- padding: 10px 12px 0 12px;
- height: 80px;
- background: #fff;
- box-sizing: border-box;
- box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, 0.4);
- .bottom-btn {
- padding: 0 30px;
- height: 40px;
- line-height: 40px;
- font-size: 14px;
- border-radius: 25px;
- text-align: center;
- }
- .secondary-btn {
- color: #2199f8;
- background: #fff;
- border: 1px solid #2199f8;
- }
- .primary-btn {
- background: #2199f8;
- color: #fff;
- &.disabled {
- opacity: 0.6;
- pointer-events: none;
- }
- }
- }
- }
- </style>
- <style lang="scss">
- .variety-select-popper {
- width: auto !important;
- min-width: 100px !important;
- }
- </style>
|