|
|
@@ -0,0 +1,666 @@
|
|
|
+<template>
|
|
|
+ <div class="manual-farming">
|
|
|
+ <div class="manual-farming__content">
|
|
|
+ <div class="page-header">
|
|
|
+ <div class="page-title">完善人工农事服务</div>
|
|
|
+ <div class="page-subtitle">让农事调度更高效(可多选)</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="showAddPopup = true">+ 添加农事</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="task-card" v-if="!isFruitView">
|
|
|
+ <div class="tag-group">
|
|
|
+ <div
|
|
|
+ v-for="item in displayFieldTasks"
|
|
|
+ :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 v-if="!displayFieldTasks.length" class="empty-tip">暂无匹配农事</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else class="fruit-list">
|
|
|
+ <div v-for="group in displayFruitGroups" :key="group.name" class="task-card fruit-card">
|
|
|
+ <div class="section-title">
|
|
|
+ <img class="title-icon" src="@/assets/img/home/label-icon.png" alt="" />
|
|
|
+ <span>{{ group.name }}</span>
|
|
|
+ </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="!displayFruitGroups.length" class="empty-tip">暂无匹配农事</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="custom-bottom-fixed-btns">
|
|
|
+ <div class="bottom-btn secondary-btn" @click="handlePrevClick">上一步</div>
|
|
|
+ <div class="bottom-btn primary-btn" :class="{ disabled: submitting }" @click="handlePrimaryClick">
|
|
|
+ {{ primaryBtnText }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <popup
|
|
|
+ v-model:show="showAddPopup"
|
|
|
+ round
|
|
|
+ closeable
|
|
|
+ class="add-task-popup"
|
|
|
+ :close-on-click-overlay="false"
|
|
|
+ teleport="body"
|
|
|
+ >
|
|
|
+ <div class="add-task-popup__content">
|
|
|
+ <div class="form-block__title">农事名称</div>
|
|
|
+ <el-input v-model="newTaskName" placeholder="请输入农事名称" />
|
|
|
+ <div class="add-task-popup__confirm" @click="handleAddConfirm">确认</div>
|
|
|
+ </div>
|
|
|
+ </popup>
|
|
|
+
|
|
|
+ <tip-popup
|
|
|
+ v-model:show="showSuccessPopup"
|
|
|
+ type="executeSuccess"
|
|
|
+ text="您的信息已提交成功"
|
|
|
+ buttonText="完成"
|
|
|
+ @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 { Popup } from "vant";
|
|
|
+import tipPopup from "@/components/popup/tipPopup.vue";
|
|
|
+
|
|
|
+const TASK_KEY = "ENTRY_SELECTED_FARM_TASKS";
|
|
|
+const TASK_VIEW_KEY = "ENTRY_MANUAL_VIEW";
|
|
|
+const EQUIPMENT_KEY = "ENTRY_SELECTED_EQUIPMENT";
|
|
|
+const SELECTED_LIST_KEY = "ENTRY_SELECTED_VARIETY_LIST";
|
|
|
+const CATEGORY_SESSION_KEY = "ENTRY_SELECTED_CATEGORY";
|
|
|
+const LOCATION_KEY = "ENTRY_RESIDENT_LOCATION";
|
|
|
+const EDIT_UID_KEY = "ENTRY_VARIETY_EDIT_UID";
|
|
|
+const STEP_KEY = "ENTRY_INFORMATION_STEP";
|
|
|
+
|
|
|
+const emit = defineEmits(["prev", "next", "confirm"]);
|
|
|
+const props = defineProps({
|
|
|
+ hasField: { type: Boolean, default: false },
|
|
|
+ hasFruit: { type: Boolean, default: false },
|
|
|
+});
|
|
|
+
|
|
|
+const FIELD_TASKS = [
|
|
|
+ { id: 1, name: "人工补苗" },
|
|
|
+ { id: 2, name: "人工授粉" },
|
|
|
+ { id: 3, name: "人工除草" },
|
|
|
+ { id: 4, name: "清沟修渠" },
|
|
|
+ { id: 5, name: "排水晒田" },
|
|
|
+ { id: 6, name: "甘蔗砍收" },
|
|
|
+ { id: 7, name: "棉花采摘" },
|
|
|
+];
|
|
|
+
|
|
|
+const FRUIT_GROUPS = [
|
|
|
+ {
|
|
|
+ name: "树体管理",
|
|
|
+ items: [
|
|
|
+ { id: 201, name: "整形修剪" },
|
|
|
+ { id: 202, name: "嫁接" },
|
|
|
+ { id: 203, name: "环割环剥" },
|
|
|
+ { id: 204, name: "枝梢管理" },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "花果管理",
|
|
|
+ items: [
|
|
|
+ { id: 301, name: "疏花疏果" },
|
|
|
+ { id: 302, name: "果实套袋" },
|
|
|
+ { id: 303, name: "人工授粉" },
|
|
|
+ { id: 304, name: "果实增色" },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "采收与园地管理",
|
|
|
+ items: [
|
|
|
+ { id: 401, name: "人工采摘" },
|
|
|
+ { id: 402, name: "清园" },
|
|
|
+ { id: 403, name: "清沟修渠" },
|
|
|
+ { id: 404, name: "摇花抖水" },
|
|
|
+ { id: 405, name: "葡萄绑蔓/夏剪" },
|
|
|
+ { id: 406, name: "防寒保暖" },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "其他人工服务",
|
|
|
+ items: [
|
|
|
+ { id: 501, name: "补植/定植" },
|
|
|
+ { id: 502, name: "行间中耕松土" },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+const searchKeyword = ref("");
|
|
|
+const appliedKeyword = ref("");
|
|
|
+const selectedIds = reactive(new Set());
|
|
|
+const fieldTaskList = ref(FIELD_TASKS.map((item) => ({ ...item })));
|
|
|
+const fruitGroups = ref(FRUIT_GROUPS.map((group) => ({
|
|
|
+ name: group.name,
|
|
|
+ items: group.items.map((item) => ({ ...item })),
|
|
|
+})));
|
|
|
+const showAddPopup = ref(false);
|
|
|
+const newTaskName = ref("");
|
|
|
+const submitting = ref(false);
|
|
|
+const showSuccessPopup = ref(false);
|
|
|
+const currentView = ref("field");
|
|
|
+let customTaskId = 900;
|
|
|
+
|
|
|
+const isFruitView = computed(() => currentView.value === "fruit");
|
|
|
+const needFruitAfterField = computed(() => props.hasField && props.hasFruit);
|
|
|
+const isLastTaskView = computed(() => !props.hasFruit);
|
|
|
+const primaryBtnText = computed(() => {
|
|
|
+ if (submitting.value) return "提交中...";
|
|
|
+ if (isLastTaskView.value) return "提交信息";
|
|
|
+ if (needFruitAfterField.value) {
|
|
|
+ return isFruitView.value ? "下一步 (5/6)" : "下一步 (4/6)";
|
|
|
+ }
|
|
|
+ return "下一步 (3/4)";
|
|
|
+});
|
|
|
+
|
|
|
+const displayFieldTasks = computed(() => {
|
|
|
+ const keyword = (appliedKeyword.value || "").trim();
|
|
|
+ if (!keyword) return fieldTaskList.value;
|
|
|
+ return fieldTaskList.value.filter((item) => item.name.includes(keyword));
|
|
|
+});
|
|
|
+
|
|
|
+const displayFruitGroups = computed(() => {
|
|
|
+ const keyword = (appliedKeyword.value || "").trim();
|
|
|
+ const groups = fruitGroups.value.map((group) => ({
|
|
|
+ ...group,
|
|
|
+ items: keyword ? group.items.filter((item) => item.name.includes(keyword)) : group.items,
|
|
|
+ }));
|
|
|
+ return groups.filter((group) => group.items.length);
|
|
|
+});
|
|
|
+
|
|
|
+const allFruitTasks = computed(() => fruitGroups.value.flatMap((group) => group.items));
|
|
|
+
|
|
|
+function readJson(key) {
|
|
|
+ try {
|
|
|
+ const raw = sessionStorage.getItem(key);
|
|
|
+ return raw ? JSON.parse(raw) : null;
|
|
|
+ } catch {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function restoreSelection() {
|
|
|
+ const cached = readJson(TASK_KEY);
|
|
|
+ const list = Array.isArray(cached)
|
|
|
+ ? cached
|
|
|
+ : [...(cached?.field || []), ...(cached?.fruit || [])];
|
|
|
+ list.forEach((item) => {
|
|
|
+ if (item?.id == null) return;
|
|
|
+ selectedIds.add(String(item.id));
|
|
|
+ if (item.scope === "fruit" || Number(item.id) >= 200) {
|
|
|
+ const exists = allFruitTasks.value.some((row) => String(row.id) === String(item.id));
|
|
|
+ if (!exists) {
|
|
|
+ fruitGroups.value[fruitGroups.value.length - 1].items.push({
|
|
|
+ id: item.id,
|
|
|
+ name: item.name,
|
|
|
+ custom: true,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!fieldTaskList.value.some((row) => String(row.id) === String(item.id))) {
|
|
|
+ fieldTaskList.value.push({ id: item.id, name: item.name, custom: true });
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function saveSelectionDraft() {
|
|
|
+ const field = fieldTaskList.value
|
|
|
+ .filter((item) => selectedIds.has(String(item.id)))
|
|
|
+ .map((item) => ({ ...item, scope: "field" }));
|
|
|
+ const fruit = allFruitTasks.value
|
|
|
+ .filter((item) => selectedIds.has(String(item.id)))
|
|
|
+ .map((item) => ({ ...item, scope: "fruit" }));
|
|
|
+ sessionStorage.setItem(TASK_KEY, JSON.stringify({ field, fruit }));
|
|
|
+}
|
|
|
+
|
|
|
+const handleSearch = () => {
|
|
|
+ appliedKeyword.value = searchKeyword.value.trim();
|
|
|
+};
|
|
|
+
|
|
|
+const toggleSelect = (item) => {
|
|
|
+ const id = String(item.id);
|
|
|
+ if (selectedIds.has(id)) selectedIds.delete(id);
|
|
|
+ else selectedIds.add(id);
|
|
|
+ saveSelectionDraft();
|
|
|
+};
|
|
|
+
|
|
|
+const handleAddConfirm = () => {
|
|
|
+ const name = String(newTaskName.value || "").trim();
|
|
|
+ if (!name) {
|
|
|
+ ElMessage.warning("请输入农事名称");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const list = isFruitView.value ? allFruitTasks.value : fieldTaskList.value;
|
|
|
+ const exists = list.find((item) => item.name === name);
|
|
|
+ if (exists) {
|
|
|
+ selectedIds.add(String(exists.id));
|
|
|
+ saveSelectionDraft();
|
|
|
+ ElMessage.success("已选中该农事");
|
|
|
+ showAddPopup.value = false;
|
|
|
+ newTaskName.value = "";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const newItem = { id: ++customTaskId, name, custom: true };
|
|
|
+ if (isFruitView.value) {
|
|
|
+ fruitGroups.value[fruitGroups.value.length - 1].items.push(newItem);
|
|
|
+ } else {
|
|
|
+ fieldTaskList.value.push(newItem);
|
|
|
+ }
|
|
|
+ selectedIds.add(String(newItem.id));
|
|
|
+ saveSelectionDraft();
|
|
|
+ showAddPopup.value = false;
|
|
|
+ newTaskName.value = "";
|
|
|
+ ElMessage.success("添加成功");
|
|
|
+};
|
|
|
+
|
|
|
+function getVarietyDraftList() {
|
|
|
+ const draft = readJson(SELECTED_LIST_KEY);
|
|
|
+ if (Array.isArray(draft)) return draft;
|
|
|
+ if (Array.isArray(draft?.list)) return draft.list;
|
|
|
+ return [];
|
|
|
+}
|
|
|
+
|
|
|
+function getPhenophaseLabel(item) {
|
|
|
+ return item.phenophase || item.phenologyName || String(item.phenologyId || "");
|
|
|
+}
|
|
|
+
|
|
|
+function buildPlotPayload() {
|
|
|
+ const baForm = readJson("ENTRY_BA_FORM") || {};
|
|
|
+ const varietyList = getVarietyDraftList();
|
|
|
+ const equipmentCache = readJson(EQUIPMENT_KEY);
|
|
|
+ const equipmentList = Array.isArray(equipmentCache)
|
|
|
+ ? equipmentCache
|
|
|
+ : [...(equipmentCache?.field || []), ...(equipmentCache?.fruit || [])];
|
|
|
+ const fieldSelected = fieldTaskList.value.filter((item) => selectedIds.has(String(item.id)));
|
|
|
+ const fruitSelected = allFruitTasks.value.filter((item) => selectedIds.has(String(item.id)));
|
|
|
+ const taskSelected = [...fieldSelected, ...fruitSelected];
|
|
|
+ return {
|
|
|
+ user_name: baForm.name,
|
|
|
+ tel: baForm.phone,
|
|
|
+ team_name: baForm.teamName || "",
|
|
|
+ team_type: baForm.teamType || "",
|
|
|
+ invite_type: baForm.inviteType || "service",
|
|
|
+ crops: varietyList.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,
|
|
|
+ })),
|
|
|
+ farm_machines: equipmentList.map((item) => ({ id: item.id, name: item.name })),
|
|
|
+ farm_tasks: taskSelected.map((item) => ({ id: item.id, name: item.name })),
|
|
|
+ field_tasks: fieldSelected.map((item) => ({ id: item.id, name: item.name })),
|
|
|
+ fruit_tasks: fruitSelected.map((item) => ({ id: item.id, name: item.name })),
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function 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);
|
|
|
+ sessionStorage.removeItem(EQUIPMENT_KEY);
|
|
|
+ sessionStorage.removeItem(TASK_KEY);
|
|
|
+ sessionStorage.removeItem(TASK_VIEW_KEY);
|
|
|
+ sessionStorage.removeItem(STEP_KEY);
|
|
|
+ sessionStorage.removeItem("ENTRY_INVITE_TYPE");
|
|
|
+}
|
|
|
+
|
|
|
+const handleSubmit = () => {
|
|
|
+ if (submitting.value) return;
|
|
|
+ const baForm = readJson("ENTRY_BA_FORM");
|
|
|
+ if (!baForm?.name || !baForm?.phone) {
|
|
|
+ ElMessage.warning("请先完善个人信息");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ submitting.value = true;
|
|
|
+ try {
|
|
|
+ const params = buildPlotPayload();
|
|
|
+ console.log("entry submit params", params);
|
|
|
+ showSuccessPopup.value = true;
|
|
|
+ clearEntrySession();
|
|
|
+ } catch (error) {
|
|
|
+ console.error("entry submit failed", error);
|
|
|
+ ElMessage.error("提交失败");
|
|
|
+ } finally {
|
|
|
+ submitting.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const handleComplete = () => {
|
|
|
+ showSuccessPopup.value = false;
|
|
|
+ emit("confirm");
|
|
|
+};
|
|
|
+
|
|
|
+const handlePrevClick = () => {
|
|
|
+ if (isFruitView.value && props.hasField) {
|
|
|
+ currentView.value = "field";
|
|
|
+ sessionStorage.setItem(TASK_VIEW_KEY, "field");
|
|
|
+ searchKeyword.value = "";
|
|
|
+ appliedKeyword.value = "";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ sessionStorage.removeItem(TASK_VIEW_KEY);
|
|
|
+ emit("prev");
|
|
|
+};
|
|
|
+
|
|
|
+const handlePrimaryClick = () => {
|
|
|
+ saveSelectionDraft();
|
|
|
+ if (!isLastTaskView.value) {
|
|
|
+ if (needFruitAfterField.value && !isFruitView.value) {
|
|
|
+ currentView.value = "fruit";
|
|
|
+ sessionStorage.setItem(TASK_VIEW_KEY, "fruit");
|
|
|
+ searchKeyword.value = "";
|
|
|
+ appliedKeyword.value = "";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ sessionStorage.setItem(TASK_VIEW_KEY, currentView.value);
|
|
|
+ emit("next");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ handleSubmit();
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const savedView = sessionStorage.getItem(TASK_VIEW_KEY);
|
|
|
+ if (savedView === "fruit" && props.hasFruit) {
|
|
|
+ currentView.value = "fruit";
|
|
|
+ } else {
|
|
|
+ currentView.value = props.hasField ? "field" : "fruit";
|
|
|
+ }
|
|
|
+ restoreSelection();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.manual-farming {
|
|
|
+ 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: 8px 16px 80px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-header {
|
|
|
+ padding: 8px 4px 16px;
|
|
|
+
|
|
|
+ .page-title {
|
|
|
+ font-size: 26px;
|
|
|
+ color: #005599;
|
|
|
+ font-family: "PangMenZhengDao";
|
|
|
+ line-height: 36px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-subtitle {
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #005599;
|
|
|
+ line-height: 22px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .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;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-card {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 14px 12px 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fruit-card {
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .section-title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1a1a1a;
|
|
|
+
|
|
|
+ .title-icon {
|
|
|
+ width: 15px;
|
|
|
+ height: 15px;
|
|
|
+ object-fit: contain;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .tag-group {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(3, 1fr);
|
|
|
+ gap: 0 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .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;
|
|
|
+ color: #000;
|
|
|
+ background: #f3f4f6;
|
|
|
+ border: 1px solid transparent;
|
|
|
+
|
|
|
+ .text {
|
|
|
+ font-size: 13px;
|
|
|
+ line-height: 16px;
|
|
|
+ padding: 0 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.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);
|
|
|
+
|
|
|
+ .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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.add-task-popup {
|
|
|
+ width: 330px;
|
|
|
+
|
|
|
+ .van-popup__close-icon {
|
|
|
+ color: #333;
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__content {
|
|
|
+ padding: 24px 16px 20px;
|
|
|
+ background: linear-gradient(360deg, #ffffff 74.2%, #d1ebff 100%);
|
|
|
+ border-radius: 16px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-block__title {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #000;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input__wrapper {
|
|
|
+ min-height: 40px;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset;
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__confirm {
|
|
|
+ margin-top: 24px;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 25px;
|
|
|
+ background: #2199f8;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 16px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|