|
@@ -1,980 +0,0 @@
|
|
|
-<template>
|
|
|
|
|
- <div class="select-equipment" :class="{ 'is-service-equipment': isService }">
|
|
|
|
|
- <div class="select-equipment__content">
|
|
|
|
|
- <div class="page-header">
|
|
|
|
|
- <div class="page-title has-tag-wrap">
|
|
|
|
|
- 完善设备信息
|
|
|
|
|
- <span v-if="cropGroupLabel" class="page-tag">{{ cropGroupLabel }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="page-title">让农机调度更精准<span class="page-tag-tip">(可多选)</span></div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="toolbar">
|
|
|
|
|
- <div class="search-bar">
|
|
|
|
|
- <el-icon class="search-icon"><Search /></el-icon>
|
|
|
|
|
- <input
|
|
|
|
|
- v-model="searchKeyword"
|
|
|
|
|
- class="search-input"
|
|
|
|
|
- type="text"
|
|
|
|
|
- placeholder="请输入农机名称"
|
|
|
|
|
- @keyup.enter="handleSearch"
|
|
|
|
|
- />
|
|
|
|
|
- <div class="search-btn" @click="handleSearch">搜索</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="add-btn" @click="handleAddMachine">+ 添加农机</div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="equipment-list" v-loading="loading">
|
|
|
|
|
- <div v-for="group in displayGroups" :key="group.name" class="equipment-card">
|
|
|
|
|
- <div class="section-title">
|
|
|
|
|
- <img class="title-icon" src="@/assets/img/home/label-icon.png" alt="" />
|
|
|
|
|
- <span>{{ group.name }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div v-if="group.desc" class="section-desc">{{ group.desc }}</div>
|
|
|
|
|
- <div class="tag-group">
|
|
|
|
|
- <div
|
|
|
|
|
- v-for="item in group.items"
|
|
|
|
|
- :key="item.id"
|
|
|
|
|
- class="tag-item"
|
|
|
|
|
- :class="{ selected: selectedIds.has(String(item.id)) }"
|
|
|
|
|
- @click="toggleSelect(item)"
|
|
|
|
|
- >
|
|
|
|
|
- <span class="text">{{ item.name }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div v-if="!loading && !displayGroups.length" class="empty-tip">暂无匹配农机</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="custom-bottom-fixed-btns">
|
|
|
|
|
- <div class="btns-l">
|
|
|
|
|
- <div class="bottom-btn secondary-btn" @click="emit('prev')">上一步</div>
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="isLastStep && !isService"
|
|
|
|
|
- class="bottom-btn secondary-btn"
|
|
|
|
|
- :class="{ disabled: submitting }"
|
|
|
|
|
- @click="handleSkip"
|
|
|
|
|
- >
|
|
|
|
|
- 跳过
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="bottom-btn primary-btn" :class="{ disabled: submitting }" @click="handleSubmit">
|
|
|
|
|
- {{ primaryBtnText }}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <add-machine-popup
|
|
|
|
|
- v-model:show="showAddPopup"
|
|
|
|
|
- @confirm="handleAddConfirm"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <tip-popup
|
|
|
|
|
- v-model:show="showSuccessPopup"
|
|
|
|
|
- type="executeSuccess"
|
|
|
|
|
- :text="isService ? '您的信息已提交成功' : '您的信息已上传'"
|
|
|
|
|
- :text2="isService ? '' : '请等待诊断报告生成'"
|
|
|
|
|
- buttonText="完成"
|
|
|
|
|
- :close-on-click-overlay="false"
|
|
|
|
|
- @confirm="handleComplete"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- </div>
|
|
|
|
|
-</template>
|
|
|
|
|
-
|
|
|
|
|
-<script setup>
|
|
|
|
|
-import { computed, onMounted, reactive, ref } from "vue";
|
|
|
|
|
-import { ElMessage } from "element-plus";
|
|
|
|
|
-import { Search } from "@element-plus/icons-vue";
|
|
|
|
|
-import addMachinePopup from "./addMachinePopup.vue";
|
|
|
|
|
-import tipPopup from "@/components/popup/tipPopup.vue";
|
|
|
|
|
-import { selectNewlyCreatedFarm } from "@/utils/selectedFarm";
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// Props / Emits
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-const emit = defineEmits(["prev", "next", "confirm"]);
|
|
|
|
|
-const props = defineProps({
|
|
|
|
|
- /** 农服录入:大田/果树分步选设备;农户录入为 false */
|
|
|
|
|
- isService: { type: Boolean, default: false },
|
|
|
|
|
- /** 当前是否为录入流程最后一步(决定主按钮文案与是否可提交) */
|
|
|
|
|
- isLastStep: { type: Boolean, default: true },
|
|
|
|
|
- /** 农服场景下的设备范围:field | fruit | "" */
|
|
|
|
|
- equipmentScope: { type: String, default: "" },
|
|
|
|
|
- totalSteps: { type: Number, default: 4 },
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// Session 键名(与录入流程其他步骤共享)
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-const SESSION = {
|
|
|
|
|
- EQUIPMENT: "ENTRY_SELECTED_EQUIPMENT",
|
|
|
|
|
- TASK: "ENTRY_SELECTED_FARM_TASKS",
|
|
|
|
|
- VARIETY: "ENTRY_SELECTED_VARIETY_LIST",
|
|
|
|
|
- CATEGORY: "ENTRY_SELECTED_CATEGORY",
|
|
|
|
|
- LOCATION: "ENTRY_RESIDENT_LOCATION",
|
|
|
|
|
- EDIT_UID: "ENTRY_VARIETY_EDIT_UID",
|
|
|
|
|
- STEP: "ENTRY_INFORMATION_STEP",
|
|
|
|
|
- BA_FORM: "ENTRY_BA_FORM",
|
|
|
|
|
- MANUAL_VIEW: "ENTRY_MANUAL_VIEW",
|
|
|
|
|
- INVITE_TYPE: "ENTRY_INVITE_TYPE",
|
|
|
|
|
- ADMIN_ID: "ENTRY_ADMIN_ID",
|
|
|
|
|
- /** farmer_crop_detail 返回的品类详情,按 crop_id 缓存 */
|
|
|
|
|
- CROP_DETAIL: "ENTRY_CROP_DETAIL",
|
|
|
|
|
- /** crops 接口返回的城市等元信息 */
|
|
|
|
|
- CROP_META: "ENTRY_CROP_META",
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-/** 用户手动添加的农机归入此分组,始终置顶 */
|
|
|
|
|
-const CUSTOM_GROUP_NAME = "我的农机";
|
|
|
|
|
-/** 自定义农机 ID 起始值,避免与接口 machine_id 冲突 */
|
|
|
|
|
-const CUSTOM_MACHINE_ID_START = 9000;
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// 页面状态
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-const loading = ref(false);
|
|
|
|
|
-const submitting = ref(false);
|
|
|
|
|
-const showAddPopup = ref(false);
|
|
|
|
|
-const showSuccessPopup = ref(false);
|
|
|
|
|
-const searchKeyword = ref("");
|
|
|
|
|
-const appliedKeyword = ref("");
|
|
|
|
|
-/** 已选农机 ID 集合(Set 便于 O(1) 切换) */
|
|
|
|
|
-const selectedIds = reactive(new Set());
|
|
|
|
|
-/** 按农事阶段分组的农机列表(接口 + 自定义项) */
|
|
|
|
|
-const equipmentGroups = ref([]);
|
|
|
|
|
-/** 页头品类标签,如「大田类」 */
|
|
|
|
|
-const cropGroupLabel = ref("");
|
|
|
|
|
-let customMachineId = CUSTOM_MACHINE_ID_START;
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// 计算属性
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-/** 按关键词过滤后的展示分组 */
|
|
|
|
|
-const displayGroups = computed(() => {
|
|
|
|
|
- const keyword = appliedKeyword.value.trim();
|
|
|
|
|
- if (!keyword) return equipmentGroups.value;
|
|
|
|
|
- return equipmentGroups.value
|
|
|
|
|
- .map((group) => ({
|
|
|
|
|
- ...group,
|
|
|
|
|
- items: group.items.filter((item) => item.name.includes(keyword)),
|
|
|
|
|
- }))
|
|
|
|
|
- .filter((group) => group.items.length);
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-/** 扁平化所有农机项,供选中态与草稿保存使用 */
|
|
|
|
|
-const allEquipmentItems = computed(() =>
|
|
|
|
|
- equipmentGroups.value.flatMap((group) => group.items)
|
|
|
|
|
-);
|
|
|
|
|
-
|
|
|
|
|
-const primaryBtnText = computed(() => {
|
|
|
|
|
- if (submitting.value) return "提交中...";
|
|
|
|
|
- if (props.isLastStep) return "提交信息";
|
|
|
|
|
- const total = props.isService ? props.totalSteps : props.totalSteps || 3;
|
|
|
|
|
- return `下一步 (3/${total})`;
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// Session 读写
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-function readJson(key) {
|
|
|
|
|
- try {
|
|
|
|
|
- const raw = sessionStorage.getItem(key);
|
|
|
|
|
- return raw ? JSON.parse(raw) : null;
|
|
|
|
|
- } catch {
|
|
|
|
|
- return null;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function writeJson(key, value) {
|
|
|
|
|
- sessionStorage.setItem(key, JSON.stringify(value));
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// 品类与设备范围(农服分大田/果树两步)
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-function getSelectedCategories() {
|
|
|
|
|
- const list = readJson(SESSION.CATEGORY);
|
|
|
|
|
- return Array.isArray(list) ? list : [];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function isFieldCategory(item) {
|
|
|
|
|
- return item?.firstCrop === "大田" || item?.majorKey === "field";
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function isFruitCategory(item) {
|
|
|
|
|
- return item?.firstCrop === "果树" || item?.majorKey === "fruit";
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 当前步骤应对应的品类:农服按 scope 取大田/果树,农户取第一个 */
|
|
|
|
|
-function getCategoryForMachines() {
|
|
|
|
|
- const categories = getSelectedCategories();
|
|
|
|
|
- const scope = getCurrentScope();
|
|
|
|
|
- if (scope === "fruit") return categories.find(isFruitCategory) ?? null;
|
|
|
|
|
- if (scope === "field") return categories.find(isFieldCategory) ?? null;
|
|
|
|
|
- return categories[0] ?? null;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function getCurrentScope() {
|
|
|
|
|
- if (props.equipmentScope === "fruit") return "fruit";
|
|
|
|
|
- if (props.equipmentScope === "field") return "field";
|
|
|
|
|
- return "";
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// 农机数据结构转换
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-/** 接口 machines(按 stage 分组)→ 页面分组结构 */
|
|
|
|
|
-function mapMachinesToGroups(machines) {
|
|
|
|
|
- if (!Array.isArray(machines)) return [];
|
|
|
|
|
- return machines
|
|
|
|
|
- .map((group) => ({
|
|
|
|
|
- name: group.stage || "",
|
|
|
|
|
- desc: "",
|
|
|
|
|
- items: (group.items || []).map((item) => ({
|
|
|
|
|
- id: item.machine_id,
|
|
|
|
|
- name: item.display_name || item.machine_name || "",
|
|
|
|
|
- machineName: item.machine_name || "",
|
|
|
|
|
- isCropSpecific: !!item.is_crop_specific,
|
|
|
|
|
- })),
|
|
|
|
|
- }))
|
|
|
|
|
- .filter((group) => group.name && group.items.length);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 农服缓存为 { field, fruit };农户为数组 */
|
|
|
|
|
-function isScopedEquipmentCache(cached) {
|
|
|
|
|
- return cached && !Array.isArray(cached) && (cached.field || cached.fruit);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function flattenEquipment(cached) {
|
|
|
|
|
- if (!cached) return [];
|
|
|
|
|
- if (Array.isArray(cached)) return cached;
|
|
|
|
|
- return [...(cached.field || []), ...(cached.fruit || [])];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function getScopeEquipmentList(cached, scope) {
|
|
|
|
|
- if (!cached) return [];
|
|
|
|
|
- if (Array.isArray(cached)) return scope === "fruit" ? [] : cached;
|
|
|
|
|
- return cached[scope] || [];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function findGroupByItemId(itemId) {
|
|
|
|
|
- return equipmentGroups.value.find((group) =>
|
|
|
|
|
- group.items.some((row) => String(row.id) === String(itemId))
|
|
|
|
|
- );
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updateCropGroupLabel(category, apiCropGroup) {
|
|
|
|
|
- if (apiCropGroup) {
|
|
|
|
|
- cropGroupLabel.value = `${apiCropGroup}类`;
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- cropGroupLabel.value =
|
|
|
|
|
- category?.majorLabel ||
|
|
|
|
|
- (category?.firstCrop ? `${category.firstCrop}类` : "");
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 缓存 farmer_crop_detail 品类信息,供提交时取 crop_code / crop_group */
|
|
|
|
|
-function saveCropDetail(data) {
|
|
|
|
|
- if (data?.crop_id == null || data?.crop_id === "") return;
|
|
|
|
|
- const cache = readJson(SESSION.CROP_DETAIL) || {};
|
|
|
|
|
- cache[String(data.crop_id)] = {
|
|
|
|
|
- crop_id: data.crop_id,
|
|
|
|
|
- crop_code: data.crop_code || "",
|
|
|
|
|
- crop_group: data.crop_group || "",
|
|
|
|
|
- crop_name: data.crop_name || "",
|
|
|
|
|
- crop_type: data.crop_type || "",
|
|
|
|
|
- };
|
|
|
|
|
- writeJson(SESSION.CROP_DETAIL, cache);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function getCropDetailMap() {
|
|
|
|
|
- const cache = readJson(SESSION.CROP_DETAIL);
|
|
|
|
|
- return cache && typeof cache === "object" ? cache : {};
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// 选中态:恢复 / 持久化
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-/** 从 session 恢复当前 scope 下的选中项;自定义项若不在列表中则补回分组 */
|
|
|
|
|
-function restoreSelection() {
|
|
|
|
|
- const cached = readJson(SESSION.EQUIPMENT);
|
|
|
|
|
- const scope = getCurrentScope();
|
|
|
|
|
- const list = scope ? getScopeEquipmentList(cached, scope) : flattenEquipment(cached);
|
|
|
|
|
-
|
|
|
|
|
- list.forEach((item) => {
|
|
|
|
|
- if (item?.id == null) return;
|
|
|
|
|
- selectedIds.add(String(item.id));
|
|
|
|
|
-
|
|
|
|
|
- if (!item.custom) return;
|
|
|
|
|
- const exists = allEquipmentItems.value.some(
|
|
|
|
|
- (row) => String(row.id) === String(item.id)
|
|
|
|
|
- );
|
|
|
|
|
- if (exists) return;
|
|
|
|
|
-
|
|
|
|
|
- const group =
|
|
|
|
|
- equipmentGroups.value.find((row) => row.name === item.groupName) ||
|
|
|
|
|
- equipmentGroups.value.at(-1);
|
|
|
|
|
- group?.items.push({ id: item.id, name: item.name, custom: true });
|
|
|
|
|
-
|
|
|
|
|
- if (Number(item.id) >= customMachineId) {
|
|
|
|
|
- customMachineId = Number(item.id);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/**
|
|
|
|
|
- * 果树步骤:大田已选且当前果树列表中存在的设备(同 machine_id 或同名)默认勾选
|
|
|
|
|
- * 仅做加法,不取消果树侧已有选择
|
|
|
|
|
- */
|
|
|
|
|
-function applyFieldOverlapSelection() {
|
|
|
|
|
- if (getCurrentScope() !== "fruit") return;
|
|
|
|
|
-
|
|
|
|
|
- const fieldList = getScopeEquipmentList(readJson(SESSION.EQUIPMENT), "field");
|
|
|
|
|
- if (!fieldList.length) return;
|
|
|
|
|
-
|
|
|
|
|
- const fieldIds = new Set(
|
|
|
|
|
- fieldList.filter((item) => item?.id != null).map((item) => String(item.id))
|
|
|
|
|
- );
|
|
|
|
|
- const fieldNames = new Set(
|
|
|
|
|
- fieldList.map((item) => item?.name).filter(Boolean)
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- let changed = false;
|
|
|
|
|
- allEquipmentItems.value.forEach((item) => {
|
|
|
|
|
- const id = String(item.id);
|
|
|
|
|
- if (selectedIds.has(id)) return;
|
|
|
|
|
- const matched =
|
|
|
|
|
- fieldIds.has(id) ||
|
|
|
|
|
- (item.name && fieldNames.has(item.name)) ||
|
|
|
|
|
- (item.machineName && fieldNames.has(item.machineName));
|
|
|
|
|
- if (!matched) return;
|
|
|
|
|
- selectedIds.add(id);
|
|
|
|
|
- changed = true;
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- if (changed) saveSelectionDraft();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 将当前选中项写入 session;农服按 field/fruit 分桶存储 */
|
|
|
|
|
-function buildSelectedEquipmentPayload() {
|
|
|
|
|
- const scope = getCurrentScope();
|
|
|
|
|
- return allEquipmentItems.value
|
|
|
|
|
- .filter((item) => selectedIds.has(String(item.id)))
|
|
|
|
|
- .map((item) => ({
|
|
|
|
|
- ...item,
|
|
|
|
|
- scope: scope || "farmer",
|
|
|
|
|
- groupName: findGroupByItemId(item.id)?.name,
|
|
|
|
|
- }));
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function saveSelectionDraft() {
|
|
|
|
|
- const selected = buildSelectedEquipmentPayload();
|
|
|
|
|
- const scope = getCurrentScope();
|
|
|
|
|
-
|
|
|
|
|
- if (!props.isService) {
|
|
|
|
|
- writeJson(SESSION.EQUIPMENT, selected);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const cached = readJson(SESSION.EQUIPMENT);
|
|
|
|
|
- const next = isScopedEquipmentCache(cached)
|
|
|
|
|
- ? { field: cached.field || [], fruit: cached.fruit || [] }
|
|
|
|
|
- : { field: Array.isArray(cached) ? cached : [], fruit: [] };
|
|
|
|
|
-
|
|
|
|
|
- if (scope === "fruit") next.fruit = selected;
|
|
|
|
|
- else next.field = selected;
|
|
|
|
|
- writeJson(SESSION.EQUIPMENT, next);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// 数据加载
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-async function fetchEquipmentList() {
|
|
|
|
|
- const category = getCategoryForMachines();
|
|
|
|
|
- const cropId = category?.id;
|
|
|
|
|
- updateCropGroupLabel(category);
|
|
|
|
|
-
|
|
|
|
|
- if (cropId == null || cropId === "") {
|
|
|
|
|
- equipmentGroups.value = [];
|
|
|
|
|
- ElMessage.warning("请先选择种植品类");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- loading.value = true;
|
|
|
|
|
- try {
|
|
|
|
|
- const res = await VE_API.entry.getMachines({ crop_id: cropId });
|
|
|
|
|
- if (res.code === 200) {
|
|
|
|
|
- const data = res.data || {};
|
|
|
|
|
- saveCropDetail(data);
|
|
|
|
|
- updateCropGroupLabel(category, data.crop_group);
|
|
|
|
|
- equipmentGroups.value = mapMachinesToGroups(data.machines);
|
|
|
|
|
- } else {
|
|
|
|
|
- equipmentGroups.value = [];
|
|
|
|
|
- ElMessage.error(res.msg || "获取农机列表失败");
|
|
|
|
|
- }
|
|
|
|
|
- } catch {
|
|
|
|
|
- equipmentGroups.value = [];
|
|
|
|
|
- ElMessage.error("获取农机列表失败,请稍后再试");
|
|
|
|
|
- } finally {
|
|
|
|
|
- loading.value = false;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// 交互:搜索 / 选择 / 自定义农机
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-function handleSearch() {
|
|
|
|
|
- appliedKeyword.value = searchKeyword.value.trim();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function handleAddMachine() {
|
|
|
|
|
- showAddPopup.value = true;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function ensureCustomGroupTop() {
|
|
|
|
|
- let customGroup = equipmentGroups.value.find((g) => g.name === CUSTOM_GROUP_NAME);
|
|
|
|
|
- if (!customGroup) {
|
|
|
|
|
- customGroup = { name: CUSTOM_GROUP_NAME, items: [] };
|
|
|
|
|
- equipmentGroups.value.unshift(customGroup);
|
|
|
|
|
- return customGroup;
|
|
|
|
|
- }
|
|
|
|
|
- const index = equipmentGroups.value.indexOf(customGroup);
|
|
|
|
|
- if (index > 0) {
|
|
|
|
|
- equipmentGroups.value.splice(index, 1);
|
|
|
|
|
- equipmentGroups.value.unshift(customGroup);
|
|
|
|
|
- }
|
|
|
|
|
- return customGroup;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function handleAddConfirm({ name }) {
|
|
|
|
|
- const machineName = String(name || "").trim();
|
|
|
|
|
- if (!machineName) return;
|
|
|
|
|
-
|
|
|
|
|
- const exists = allEquipmentItems.value.find((item) => item.name === machineName);
|
|
|
|
|
- if (exists) {
|
|
|
|
|
- selectedIds.add(String(exists.id));
|
|
|
|
|
- saveSelectionDraft();
|
|
|
|
|
- ElMessage.success("已选中该农机");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const customGroup = ensureCustomGroupTop();
|
|
|
|
|
- const newItem = { id: ++customMachineId, name: machineName, custom: true };
|
|
|
|
|
- customGroup.items.push(newItem);
|
|
|
|
|
- selectedIds.add(String(newItem.id));
|
|
|
|
|
- saveSelectionDraft();
|
|
|
|
|
- ElMessage.success("添加成功");
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function toggleSelect(item) {
|
|
|
|
|
- const id = String(item.id);
|
|
|
|
|
- if (selectedIds.has(id)) selectedIds.delete(id);
|
|
|
|
|
- else selectedIds.add(id);
|
|
|
|
|
- saveSelectionDraft();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-// 提交:组装 payload / 清 session
|
|
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
|
|
-function getVarietyDraftList() {
|
|
|
|
|
- const draft = readJson(SESSION.VARIETY);
|
|
|
|
|
- if (Array.isArray(draft)) return draft;
|
|
|
|
|
- if (Array.isArray(draft?.list)) return draft.list;
|
|
|
|
|
- return [];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function getUserId() {
|
|
|
|
|
- const id = localStorage.getItem("MINI_USER_ID");
|
|
|
|
|
- return id != null && id !== "" ? Number(id) : 0;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 邀请录入时为邀请人 id,自主录入时与 user_id 相同 */
|
|
|
|
|
-function getAdminId() {
|
|
|
|
|
- const fromSession = sessionStorage.getItem(SESSION.ADMIN_ID);
|
|
|
|
|
- if (fromSession != null && fromSession !== "") return Number(fromSession);
|
|
|
|
|
- return getUserId();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 汇总各步骤 session 数据,供 addFarmInfo 提交 */
|
|
|
|
|
-function buildFarmPayload(includeEquipment = true) {
|
|
|
|
|
- const baForm = readJson(SESSION.BA_FORM) || {};
|
|
|
|
|
- const varietyList = getVarietyDraftList().filter((item) => item?.id != null && item.id !== "");
|
|
|
|
|
- const equipmentCache = readJson(SESSION.EQUIPMENT);
|
|
|
|
|
- const equipmentList = includeEquipment ? flattenEquipment(equipmentCache) : [];
|
|
|
|
|
- const categories = readJson(SESSION.CATEGORY) || [];
|
|
|
|
|
- const location = readJson(SESSION.LOCATION);
|
|
|
|
|
- const cropDetailMap = getCropDetailMap();
|
|
|
|
|
- const taskCache = readJson(SESSION.TASK);
|
|
|
|
|
- const taskList = Array.isArray(taskCache)
|
|
|
|
|
- ? taskCache
|
|
|
|
|
- : [...(taskCache?.field || []), ...(taskCache?.fruit || [])];
|
|
|
|
|
- const farmTaskId = Number(taskList[0]?.id);
|
|
|
|
|
-
|
|
|
|
|
- const primaryCropId =
|
|
|
|
|
- varietyList[0]?.categoryId ??
|
|
|
|
|
- getCategoryForMachines()?.id ??
|
|
|
|
|
- categories[0]?.id;
|
|
|
|
|
- const primaryDetail = cropDetailMap[String(primaryCropId)] || {};
|
|
|
|
|
-
|
|
|
|
|
- const cropBigType =
|
|
|
|
|
- primaryDetail.crop_group ||
|
|
|
|
|
- varietyList.find((item) => item.firstCrop)?.firstCrop ||
|
|
|
|
|
- categories.find((item) => item.firstCrop)?.firstCrop ||
|
|
|
|
|
- "";
|
|
|
|
|
-
|
|
|
|
|
- const farmLocation =
|
|
|
|
|
- location?.point ||
|
|
|
|
|
- varietyList.find((item) => item.location)?.location ||
|
|
|
|
|
- "";
|
|
|
|
|
-
|
|
|
|
|
- const payload = {
|
|
|
|
|
- user_name: baForm.farmName || baForm.name,
|
|
|
|
|
- tel: baForm.phone || "",
|
|
|
|
|
- // admin_id: 94494,
|
|
|
|
|
- admin_id: getAdminId(),
|
|
|
|
|
- user_id: getUserId(),
|
|
|
|
|
- machine_id: equipmentList
|
|
|
|
|
- .map((item) => Number(item.id))
|
|
|
|
|
- .filter((id) => Number.isFinite(id)),
|
|
|
|
|
- farm_location: farmLocation,
|
|
|
|
|
- farm_address: location?.address || "",
|
|
|
|
|
- crop_big_type: cropBigType,
|
|
|
|
|
- crops: varietyList.map((item) => {
|
|
|
|
|
- const detail = cropDetailMap[String(item.categoryId)] || {};
|
|
|
|
|
- return {
|
|
|
|
|
- crop_type: detail.crop_name || item.categoryName,
|
|
|
|
|
- crop_code: detail.crop_code || "",
|
|
|
|
|
- crop_id: Number(item.categoryId),
|
|
|
|
|
- variety_list: String(item.varietyCode || item.id),
|
|
|
|
|
- phenophase_code: String(item.phenophaseCode || item.phenologyId || ""),
|
|
|
|
|
- };
|
|
|
|
|
- }),
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- if (Number.isFinite(farmTaskId)) {
|
|
|
|
|
- payload.farm_task_id = farmTaskId;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return payload;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 点击「完成」时用于初始化报告的参数(提交成功时缓存,清空 session 前) */
|
|
|
|
|
-const pendingReportParams = ref(null);
|
|
|
|
|
-
|
|
|
|
|
-/** 从当前 session 组装 report/generate 参数 */
|
|
|
|
|
-function buildReportParams() {
|
|
|
|
|
- const baForm = readJson(SESSION.BA_FORM) || {};
|
|
|
|
|
- const varietyList = getVarietyDraftList().filter((item) => item?.id != null && item.id !== "");
|
|
|
|
|
- const cropDetailMap = getCropDetailMap();
|
|
|
|
|
- const meta = readJson(SESSION.CROP_META) || {};
|
|
|
|
|
- const first = varietyList[0];
|
|
|
|
|
- const detail = first ? cropDetailMap[String(first.categoryId)] || {} : {};
|
|
|
|
|
-
|
|
|
|
|
- return {
|
|
|
|
|
- region: meta.city || meta.county || "",
|
|
|
|
|
- crop: detail.crop_name || first?.categoryName || "",
|
|
|
|
|
- variety: first?.name || "",
|
|
|
|
|
- tel: baForm.phone || "",
|
|
|
|
|
- farmName: baForm.farmName || baForm.name || "",
|
|
|
|
|
- };
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 从新增接口返回体解析 farm_id / zone_id(兼容 zone_ids 数组等结构) */
|
|
|
|
|
-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;
|
|
|
|
|
- // add_farm_info 实际返回 zone_ids: [1369],不是 zone_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 };
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 新增成功后触发 generate_6module,仅用接口返回的 farm_id/zone_id,不等待、不落库 */
|
|
|
|
|
-function triggerReportApis(res) {
|
|
|
|
|
- // 只认 addFarmInfo 返回值,禁止回退到旧的 selectedFarmData
|
|
|
|
|
- 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 reportParams = pendingReportParams.value || {};
|
|
|
|
|
- const generateParams = {
|
|
|
|
|
- farm_id: ids.farm_id,
|
|
|
|
|
- zone_id: ids.zone_id,
|
|
|
|
|
- region: reportParams.region || "",
|
|
|
|
|
- crop: reportParams.crop || "",
|
|
|
|
|
- };
|
|
|
|
|
- VE_API.report.generate6Module(generateParams).catch(() => {});
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 跳转长势报告前生成报告 */
|
|
|
|
|
-async function generateGrowthReport(params) {
|
|
|
|
|
- if (!params?.region || !params?.crop || !params?.variety || !params?.tel) {
|
|
|
|
|
- console.warn("generateReport skipped: missing params", params);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const raw = await VE_API.report.generateReport(params);
|
|
|
|
|
- const res = Array.isArray(raw) ? raw[0] : raw;
|
|
|
|
|
- if (res?.code !== 200) {
|
|
|
|
|
- console.warn("generateReport failed", res?.msg || res?.message || res);
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error("generateReport error", error);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function clearEntrySession() {
|
|
|
|
|
- Object.values(SESSION).forEach((key) => sessionStorage.removeItem(key));
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-async function submitEntry(includeEquipment = true) {
|
|
|
|
|
- if (submitting.value) return;
|
|
|
|
|
-
|
|
|
|
|
- if (!props.isService && !getVarietyDraftList().length) {
|
|
|
|
|
- ElMessage.warning("请先完善种植品种信息");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const baForm = readJson(SESSION.BA_FORM);
|
|
|
|
|
- if (!baForm?.farmName && !baForm?.name) {
|
|
|
|
|
- ElMessage.warning("请先完善农场信息");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- submitting.value = true;
|
|
|
|
|
- try {
|
|
|
|
|
- const params = buildFarmPayload(includeEquipment);
|
|
|
|
|
- const raw = await VE_API.entry.addFarmInfo(params);
|
|
|
|
|
- // 部分接口返回 [body, httpStatus]
|
|
|
|
|
- const res = Array.isArray(raw) ? raw[0] : raw;
|
|
|
|
|
- if (res?.code === 200) {
|
|
|
|
|
- pendingReportParams.value = buildReportParams();
|
|
|
|
|
- // 新增成功后立刻触发 generate_6module,不等待结果
|
|
|
|
|
- triggerReportApis(res);
|
|
|
|
|
- // 新增成功后拉列表,选中最后一项
|
|
|
|
|
- await selectNewlyCreatedFarm();
|
|
|
|
|
- clearEntrySession();
|
|
|
|
|
- showSuccessPopup.value = true;
|
|
|
|
|
- } else {
|
|
|
|
|
- ElMessage.error(res?.msg || res?.message || "提交失败,请稍后再试");
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error("entry submit failed", error);
|
|
|
|
|
- ElMessage.error("提交失败");
|
|
|
|
|
- } finally {
|
|
|
|
|
- submitting.value = false;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-async function handleComplete() {
|
|
|
|
|
- // 只触发初始化,不等待结果;新增已成功即可跳转
|
|
|
|
|
- generateGrowthReport(pendingReportParams.value);
|
|
|
|
|
- pendingReportParams.value = null;
|
|
|
|
|
- showSuccessPopup.value = false;
|
|
|
|
|
- emit("confirm");
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/** 农户最后一步可跳过设备选择,仍提交其余信息 */
|
|
|
|
|
-function handleSkip() {
|
|
|
|
|
- if (!props.isLastStep) {
|
|
|
|
|
- emit("next");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- submitEntry(false);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function handleSubmit() {
|
|
|
|
|
- saveSelectionDraft();
|
|
|
|
|
- if (!props.isLastStep) {
|
|
|
|
|
- emit("next");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- submitEntry(true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-onMounted(async () => {
|
|
|
|
|
- await fetchEquipmentList();
|
|
|
|
|
- restoreSelection();
|
|
|
|
|
- applyFieldOverlapSelection();
|
|
|
|
|
-});
|
|
|
|
|
-</script>
|
|
|
|
|
-
|
|
|
|
|
-<style lang="scss" scoped>
|
|
|
|
|
-.select-equipment {
|
|
|
|
|
- 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: 12px 10px 80px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .page-header {
|
|
|
|
|
- padding: 8px 0 16px;
|
|
|
|
|
-
|
|
|
|
|
- .page-title {
|
|
|
|
|
- font-size: 26px;
|
|
|
|
|
- color: #005599;
|
|
|
|
|
- font-family: "PangMenZhengDao";
|
|
|
|
|
- line-height: 30px;
|
|
|
|
|
- .page-tag-tip {
|
|
|
|
|
- font-size: 20px;
|
|
|
|
|
- }
|
|
|
|
|
- &.has-tag-wrap {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 6px;
|
|
|
|
|
- }
|
|
|
|
|
- .page-tag {
|
|
|
|
|
- height: 24px;
|
|
|
|
|
- line-height: 24px;
|
|
|
|
|
- display: inline-block;
|
|
|
|
|
- background: #2199F8;
|
|
|
|
|
- color: #FFFFFF;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- padding: 0 6px;
|
|
|
|
|
- border-radius: 4px;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .page-subtitle {
|
|
|
|
|
- margin-top: 4px;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- color: rgba(46, 46, 46, 0.4);
|
|
|
|
|
- line-height: 20px;
|
|
|
|
|
- }
|
|
|
|
|
- .text-tip {
|
|
|
|
|
- font-size: 20px;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .toolbar {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 10px;
|
|
|
|
|
- margin-bottom: 12px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .search-bar {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- min-width: 0;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- height: 36px;
|
|
|
|
|
- padding: 0 12px;
|
|
|
|
|
- background: rgba(255, 255, 255, 0.5);
|
|
|
|
|
- border: 1px solid rgba(33, 153, 248, 0.5);
|
|
|
|
|
- border-radius: 6px;
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
-
|
|
|
|
|
- .search-icon {
|
|
|
|
|
- color: rgba(0, 0, 0, 0.35);
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- margin-right: 6px;
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .search-input {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- min-width: 0;
|
|
|
|
|
- border: none;
|
|
|
|
|
- outline: none;
|
|
|
|
|
- background: transparent;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- color: #333;
|
|
|
|
|
-
|
|
|
|
|
- &::placeholder {
|
|
|
|
|
- color: rgba(0, 0, 0, 0.3);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .search-btn {
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- padding-left: 10px;
|
|
|
|
|
- color: #2199f8;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .add-btn {
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- height: 36px;
|
|
|
|
|
- padding: 0 12px;
|
|
|
|
|
- border-radius: 6px;
|
|
|
|
|
- background: #2199f8;
|
|
|
|
|
- color: #fff;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- line-height: 36px;
|
|
|
|
|
- white-space: nowrap;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .equipment-card {
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- border-radius: 12px;
|
|
|
|
|
- padding: 14px 12px 16px;
|
|
|
|
|
- margin-bottom: 12px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .section-title {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 8px;
|
|
|
|
|
- margin-bottom: 4px;
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- color: #1a1a1a;
|
|
|
|
|
-
|
|
|
|
|
- .title-icon {
|
|
|
|
|
- width: 15px;
|
|
|
|
|
- height: 15px;
|
|
|
|
|
- object-fit: contain;
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .section-desc {
|
|
|
|
|
- margin: -2px 0 2px 22px;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- color: rgba(0, 0, 0, 0.4);
|
|
|
|
|
- line-height: 18px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .tag-group {
|
|
|
|
|
- display: grid;
|
|
|
|
|
- grid-template-columns: repeat(3, 1fr);
|
|
|
|
|
- gap: 0 8px;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
-
|
|
|
|
|
- .tag-item {
|
|
|
|
|
- margin-top: 10px;
|
|
|
|
|
- position: relative;
|
|
|
|
|
- border-radius: 6px;
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
- min-height: 36px;
|
|
|
|
|
- padding: 6px 4px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- color: #000;
|
|
|
|
|
- background: #f3f4f6;
|
|
|
|
|
- border: 1px solid transparent;
|
|
|
|
|
-
|
|
|
|
|
- .text {
|
|
|
|
|
- display: block;
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- padding: 0 4px;
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- line-height: 16px;
|
|
|
|
|
- white-space: normal;
|
|
|
|
|
- word-break: break-all;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &.selected {
|
|
|
|
|
- border: 1px solid #2199f8;
|
|
|
|
|
- background: #e8f5ff;
|
|
|
|
|
- color: #2199f8;
|
|
|
|
|
-
|
|
|
|
|
- &::after {
|
|
|
|
|
- content: "";
|
|
|
|
|
- position: absolute;
|
|
|
|
|
- z-index: 9;
|
|
|
|
|
- top: -1px;
|
|
|
|
|
- right: -1px;
|
|
|
|
|
- width: 18px;
|
|
|
|
|
- height: 14px;
|
|
|
|
|
- background: url("@/assets/img/home/checked-bg-top.png") no-repeat bottom right / 18px 13px;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .empty-tip {
|
|
|
|
|
- padding: 40px 0;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- color: rgba(0, 0, 0, 0.35);
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .custom-bottom-fixed-btns {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
- align-items: baseline;
|
|
|
|
|
- gap: 10px;
|
|
|
|
|
- padding: 12px 12px 0;
|
|
|
|
|
- height: 80px;
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
- box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, 0.4);
|
|
|
|
|
- .btns-l {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 10px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .bottom-btn {
|
|
|
|
|
- padding: 0 30px;
|
|
|
|
|
- height: 40px;
|
|
|
|
|
- line-height: 40px;
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- border-radius: 25px;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- white-space: nowrap;
|
|
|
|
|
-
|
|
|
|
|
- &.disabled {
|
|
|
|
|
- opacity: 0.6;
|
|
|
|
|
- pointer-events: none;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .secondary-btn {
|
|
|
|
|
- padding: 0 26px;
|
|
|
|
|
- color: #2199f8;
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- border: 1px solid #2199f8;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .primary-btn {
|
|
|
|
|
- background: #2199f8;
|
|
|
|
|
- color: #fff;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &.is-service-equipment {
|
|
|
|
|
- .page-subtitle {
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- color: #005599;
|
|
|
|
|
- line-height: 22px;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-</style>
|
|
|