Jelajahi Sumber

feat:添加中/英切换版本

wangsisi 2 minggu lalu
induk
melakukan
13d70a6e6a

+ 11 - 6
src/components/fnHeader.vue

@@ -2,13 +2,13 @@
     <div class="header">
         <div class="title">
             <img class="logo" src="@/assets/images/common/logo.png" alt="" />
-            <span>高州"Al+低空"智慧农业标准化与溯源平台</span>
+            <span class="locale-toggle" @click="toggleLocale">{{ t('header.title') }}</span>
             <img class="logo-icon" src="@/assets/images/common/logo-icon.png" alt="" />
         </div>
         <div class="focus-farm" v-show="!hideSwitch">
             <el-select
                 v-model="farmVal"
-                placeholder="我的关注农场"
+                :placeholder="t('header.focusFarm')"
                 style="width: 189px"
                 popper-class="focus-farm-select"
                 @change="toggleFarm"
@@ -38,6 +38,9 @@ import { onMounted, onUnmounted, ref } from "vue";
 import { useRouter } from "vue-router";
 import { convertPointToArray } from "@/utils/index";
 import eventBus from "@/api/eventBus";
+import { useI18n } from "@/i18n";
+
+const { t, locale, toggleLocale } = useI18n();
 
 const router = useRouter();
 const props = defineProps({
@@ -85,9 +88,7 @@ function getCurrentFormattedTime(type) {
 function getCurrentDayOfWeek() {
     const now = new Date();
     const dayOfWeek = now.getDay();
-    const daysOfWeek = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
-
-    return daysOfWeek[dayOfWeek];
+    return t(`week.${dayOfWeek}`);
 }
 
 function formatTimeToHHmmss(date) {
@@ -174,10 +175,14 @@ onUnmounted(() => {
         width: 33px;
         height: 12px;
       }
-      span {
+      span.locale-toggle {
         margin: 0 5px;
         cursor: pointer;
         font-family: "PangMenZhengDao";
+        user-select: none;
+        &:hover {
+          opacity: 0.85;
+        }
       }
     }
       .focus-farm {

+ 24 - 17
src/components/navigation.vue

@@ -1,17 +1,17 @@
 <template>
     <div class="navigation yes-events">
         <el-select class="select" v-model="areaId" size="large" @change="changeSelect" popper-class="focus-farm-select">
-            <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
+            <el-option v-for="item in displayOptions" :key="item.id" :label="item.name" :value="item.id" />
         </el-select>
         <div class="tabs" v-for="(ele, idx) in list" :key="idx">
             <div
                 class="tab-item"
                 @click="handleHomeTab(item)"
-                :class="{ active: active === item.name }"
+                :class="{ active: active === item.nameKey }"
                 v-for="(item, index) in ele"
                 :key="index"
             >
-                {{ item.name }}
+                {{ t(item.nameKey) }}
             </div>
         </div>
         <el-checkbox-group
@@ -33,11 +33,19 @@ import { useRouter } from "vue-router";
 import { onMounted, onUnmounted, ref, computed } from "vue";
 import { useStore } from "vuex";
 import eventBus from "@/api/eventBus";
+import { useI18n } from "@/i18n";
+
+const { t } = useI18n();
 const router = useRouter();
 const store = useStore();
 
 const areaId = ref("");
 const options = ref([]);
+const displayOptions = computed(() =>
+    options.value.map((item) =>
+        item.id === 0 ? { ...item, name: t("nav.allAreas") } : item
+    )
+);
 eventBus.off('garden:organId', gardenOrganId)
 eventBus.on('garden:organId',gardenOrganId)
 
@@ -47,9 +55,9 @@ function gardenOrganId(farmId){
     VE_API.region.list({farmId}).then(res =>{
         options.value = res.data
         options.value.unshift({
-            id:0,
-            name:'全部区域'
-        })
+            id: 0,
+            name: "",
+        });
         areaId.value = res.data[0].id
         eventBus.emit('area:id',{areaId:areaId.value,farmId})
         sessionStorage.setItem('regionId',areaId.value)
@@ -96,17 +104,16 @@ function handleActive({name,key}){
 }
 
 const active = ref("");
-const handleHomeTab = ({ id, name }) => {
-    active.value = name;
+const handleHomeTab = ({ id, nameKey }) => {
+    active.value = nameKey;
     childrenData.value = []
-    const menuItem = mainMenuArr.value.find(item =>item.name===name)
+    const menuItem = mainMenuArr.value.find(item =>item.nameKey===nameKey)
     if(menuItem){
         childrenData.value = menuItem.btnGroup
         checkedChildren.value = [menuItem.btnGroup[0]];
     }
-    emit('handleTab',{name,id, legend: menuItem?.legend, colorObj: menuItem?.colorObj})
-    // eventBus.emit("changePointType", {legend: menuItem?.legend, colorObj: menuItem?.colorObj})
-    eventBus.emit('handleTab',name)
+    emit('handleTab',{name: nameKey, id, legend: menuItem?.legend, colorObj: menuItem?.colorObj})
+    eventBus.emit('handleTab', nameKey)
 };
 
 const list = ref([
@@ -126,22 +133,22 @@ const list = ref([
         //     children: ["花穗长度", "单树花穗率"],
         // },
         {
-            name: "风畅气顺",
+            nameKey: "nav.windFlow",
             id: 3,
             children: [],
         },
         {
-            name: "光透照匀",
+            nameKey: "nav.lightUniform",
             id: 4,
             children: [],
         },
         {
-            name: "益草覆盖",
+            nameKey: "nav.grassCover",
             id: 5,
             children: [],
         },
         {
-            name: "古树名木",
+            nameKey: "nav.ancientTrees",
             id: 1,
         },
     ],
@@ -164,7 +171,7 @@ const toPage = () => {
 .navigation {
     position: fixed;
     top: 34px;
-    left: 50%;
+    left: 54%;
     // left: 50%;
     transform: translateX(-50%);
     width: calc(100% - 430px * 2);

+ 39 - 0
src/i18n/index.js

@@ -0,0 +1,39 @@
+import { computed } from "vue";
+import { useStore } from "vuex";
+import messages from "./messages";
+
+function getNested(obj, path) {
+    return path.split(".").reduce((acc, key) => (acc != null ? acc[key] : undefined), obj);
+}
+
+function interpolate(text, params = {}) {
+    if (!text || typeof text !== "string") return text;
+    return text.replace(/\{(\w+)\}/g, (_, key) => (params[key] != null ? params[key] : `{${key}}`));
+}
+
+export function translate(key, params = {}, locale) {
+    const lang = locale || "zh";
+
+    if (lang === "zh") {
+        const nested = getNested(messages.zh, key);
+        if (nested != null) return interpolate(nested, params);
+        return interpolate(key, params);
+    }
+
+    const text =
+        getNested(messages.en, key) ??
+        getNested(messages.zh, key) ??
+        key;
+    return interpolate(text, params);
+}
+
+export function useI18n() {
+    const store = useStore();
+    const locale = computed(() => store.state.locale.locale);
+
+    const t = (key, params = {}) => translate(key, params, locale.value);
+
+    const toggleLocale = () => store.dispatch("locale/toggleLocale");
+
+    return { locale, t, toggleLocale };
+}

+ 430 - 0
src/i18n/messages.js

@@ -0,0 +1,430 @@
+export default {
+    zh: {
+        header: {
+            title: '溯源平台',
+            focusFarm: "我的关注农场",
+        },
+        week: {
+            0: "星期日",
+            1: "星期一",
+            2: "星期二",
+            3: "星期三",
+            4: "星期四",
+            5: "星期五",
+            6: "星期六",
+        },
+        nav: {
+            allAreas: "全部区域",
+            windFlow: "风畅气顺",
+            lightUniform: "光透照匀",
+            grassCover: "益草覆盖",
+            ancientTrees: "古树名木",
+        },
+        home: {
+            adoptManage: "认养管理",
+            tabs: {
+                adoptList: "认养列表",
+                clientList: "客户列表",
+                applyList: "认养申请",
+                addressList: "确认地址",
+            },
+            legend: {
+                notOpen: "未开放认养",
+                otherTree: "其他树",
+                pending: "待认养",
+                groupBuy: "可团购",
+                adopted: "已认养",
+                selected: "已选择",
+            },
+            tips: {
+                label: "提示:",
+                prefix: "请在底图上点选 ",
+                tree: "认养的果树",
+                middle: ",或按住 Ctrl 框选 ",
+                area: "认养的区域",
+            },
+            selectAdoptArea: "勾选认养区域",
+            cancel: "取消",
+            confirmOpenAdopt: "确认开放认养权限",
+            orchardReport: "果园报告",
+            gardenIntro: "果园介绍",
+        },
+        gardenIntroduce: {
+            gardenName: "柏桥村",
+            cropType: "白糖罂",
+            areaLabel: "果园面积:",
+            areaValue: "6800亩",
+            addressLabel: "果园地址:",
+            addressValue: "广东省茂名市高州市根子镇下辖村",
+            adoptedCount: "已认养(棵)",
+            overallScore: "综合评分(分)",
+            ecologyScore: "生态评分(分)",
+            introTitle: "果园简介",
+            edit: "编辑",
+            save: "保存",
+            medalWall: "勋章墙",
+            more: "更多",
+            honourWater: "水源洁净",
+            scenicVideo: "美景视频",
+            farmRecord: "农事记录",
+            description:
+                "柏桥村位于广东茂名高州根子镇,是千年荔枝之乡的核心产区,盛产果肉晶莹、鲜甜多汁的白糖罂荔枝。村内6800亩荔枝林与古荔园中48棵百年以上古树交相辉映,诉说着种植传奇。依托冷链物流和电商直播,新鲜荔枝一键直达全国。",
+        },
+        treeDetail: {
+            title: "果树介绍",
+            back: "返回",
+            treeAge: "树龄",
+            treeAgeValue: "10年",
+            variety: "品种",
+            uniqueCode: "唯一编码",
+            highYield: "高质产量",
+            highYieldValue: "150斤",
+            marketDate: "上市时间",
+            ecologyIndex: "生态指标",
+            progressEnded: "团购/认养已结束",
+            tracePhotos: "溯源照片",
+            more: "更多>",
+            farmEffect: "农事效果:",
+            customBtn: "我要定制",
+            tabs: {
+                all: "全部",
+                standard: "标准",
+                weather: "气象",
+            },
+            records: {
+                fruitNutrition: {
+                    name: "保果营养",
+                    effect: "提高果实质量,减少落果",
+                },
+                shakeFlower: {
+                    name: "摇花吹花",
+                    effect: "防止沤花,促进授粉",
+                },
+                killSmallLeaf: {
+                    name: "杀除小叶",
+                    effect: "促进花穗生长",
+                },
+                strongFlowerNutrition: {
+                    name: "壮花营养",
+                    effect: "培养健壮花穗",
+                },
+                wakeNutrition: {
+                    name: "催醒营养",
+                    effect: "促进花芽生长",
+                },
+                shootKill: {
+                    name: "杀梢",
+                    effect: "促进花芽分化",
+                },
+                clearGarden: {
+                    name: "清园",
+                    effect: "减少病虫害基数",
+                },
+                baseFertilizer: {
+                    name: "基肥",
+                    effect: "提供全年营养",
+                },
+                shootControl: {
+                    name: "控梢",
+                    effect: "减少病虫害基数",
+                },
+                shootPestControl: {
+                    name: "梢期防虫",
+                    effect: "减少虫害风险",
+                },
+                shootNutrition: {
+                    name: "梢期营养",
+                    effect: "减少虫害风险",
+                },
+                shootRootFertilizer: {
+                    name: "梢期根肥",
+                    effect: "增强树体营养,促进新梢健壮,增强病虫抗性",
+                },
+                fruitRootFertilizer: {
+                    name: "壮果根肥",
+                    effect: "促进果实快速膨大,提升单果重;减少生理落果与裂果,改善果实均匀度;增强抗高温/暴雨能力",
+                },
+                strongFlowerTopDress: {
+                    name: "壮花追肥",
+                    effect: "促进花穗健壮,提高雌花比例;增强花期抗低温/阴雨能力",
+                },
+                shootHeatDrought: {
+                    name: "梢期高温干旱",
+                    effect: "每日早晚树冠喷水降温(避开正午高温),以缓解高温抑制新梢生长,促进新梢抽发整齐、根系吸水效率提升",
+                },
+                fruitRainShade: {
+                    name: "果期阴雨寡照",
+                    effect: "补充叶面肥,增强光合作用,促进养分转运,避免光照不足影响,确保果实饱满、甜度高、风味佳",
+                },
+                flowerRain: {
+                    name: "花期连续阴雨",
+                    effect: "雨停间隙人工施粉或放蜂授粉,轻摇树枝排出花穗积水,防止雨水冲刷花粉和霜疫霉病蔓延,确保坐果率恢复",
+                },
+            },
+        },
+        adoptList: {
+            filters: {
+                allArea: "全区",
+                zone1: "1区",
+                zone2: "2区",
+                allCategory: "全部品类",
+                jinggang: "井岗红糯",
+                allAge: "全部树龄",
+                ageRange1: "0-10年",
+                ageRange2: "10-20年",
+                allScore: "全部评分",
+                ecologyScore: "生态评分",
+                allStatus: "全部状态",
+            },
+            placeholders: {
+                allArea: "全区",
+                allCategory: "全部品类",
+                treeAge: "树龄",
+                overallScore: "综合评分",
+                ecologyScore: "生态评分",
+                allStatus: "全部状态",
+                selectSetting: "选中设置项",
+                input: "请输入",
+            },
+            setting: "设置",
+            unpPriced: "未定价",
+            overall: "综合:",
+            ecology: "生态:",
+            points: "分",
+            unitPrice: "单价:",
+            treeAgeLabel: "树龄:",
+            totalAdopt: "总认养斤数:",
+            remaining: "剩余可购:",
+            owner: "权属人:",
+            defaultAge: "5年",
+            confirmEdit: "确认修改",
+            batchPricing: "批量定价",
+            settingType: {
+                price: "单价",
+                age: "树龄",
+                total: "认养斤数",
+            },
+            units: {
+                yuanPerJin: "元/斤",
+                year: "年",
+                jin: "斤",
+            },
+            ownerJin: "{name}({value}斤)",
+            progressRemain: "{current}/{total}斤",
+        },
+    },
+    en: {
+        header: {
+            title: 'Traceability Platform',
+            focusFarm: "My Followed Farms",
+        },
+        week: {
+            0: "Sunday",
+            1: "Monday",
+            2: "Tuesday",
+            3: "Wednesday",
+            4: "Thursday",
+            5: "Friday",
+            6: "Saturday",
+        },
+        nav: {
+            allAreas: "All Areas",
+            windFlow: "Wind Flow",
+            lightUniform: "Even Light",
+            grassCover: "Beneficial Grass",
+            ancientTrees: "Ancient Trees",
+        },
+        home: {
+            adoptManage: "Adoption Management",
+            tabs: {
+                adoptList: "Adoption List",
+                clientList: "Client List",
+                applyList: "Adoption Applications",
+                addressList: "Confirm Address",
+            },
+            legend: {
+                notOpen: "Not Open for Adoption",
+                otherTree: "Other Trees",
+                pending: "Available",
+                groupBuy: "Group Purchase Available",
+                adopted: "Adopted",
+                selected: "Selected",
+            },
+            tips: {
+                label: "Tip: ",
+                prefix: "Click on the map to select ",
+                tree: "trees for adoption",
+                middle: ", or hold Ctrl to box-select an ",
+                area: "adoption area",
+            },
+            selectAdoptArea: "Select Adoption Area",
+            cancel: "Cancel",
+            confirmOpenAdopt: "Confirm Open Adoption",
+            orchardReport: "Orchard Report",
+            gardenIntro: "Orchard Introduction",
+        },
+        gardenIntroduce: {
+            gardenName: "Baicun Village",
+            cropType: "Baitangying",
+            areaLabel: "Orchard Area: ",
+            areaValue: "6,800 mu",
+            addressLabel: "Address: ",
+            addressValue: "Baicun Village, Genzi Town, Gaozhou, Maoming, Guangdong",
+            adoptedCount: "Adopted (trees)",
+            overallScore: "Overall Score (pts)",
+            ecologyScore: "Ecology Score (pts)",
+            introTitle: "Orchard Profile",
+            edit: "Edit",
+            save: "Save",
+            medalWall: "Medal Wall",
+            more: "More",
+            honourWater: "Clean Water Source",
+            scenicVideo: "Scenic Videos",
+            farmRecord: "Farm Records",
+            description:
+                "Baicun Village in Genzi Town, Gaozhou, Maoming is a core production area of the thousand-year lychee homeland, famous for crystal-clear, sweet Baitangying lychees. Its 6,800 mu of lychee groves and 48 ancient trees over a century old in the heritage orchard tell a legendary cultivation story. With cold-chain logistics and live e-commerce, fresh lychees reach customers nationwide in one click.",
+        },
+        treeDetail: {
+            title: "Tree Profile",
+            back: "Back",
+            treeAge: "Tree Age",
+            treeAgeValue: "10 yrs",
+            variety: "Variety",
+            uniqueCode: "Unique ID",
+            highYield: "Premium Yield",
+            highYieldValue: "150 jin",
+            marketDate: "Market Date",
+            ecologyIndex: "Ecology Index",
+            progressEnded: "Group Buy / Adoption Ended",
+            tracePhotos: "Traceability Photos",
+            more: "More>",
+            farmEffect: "Farm Effect: ",
+            customBtn: "Customize",
+            tabs: {
+                all: "All",
+                standard: "Standard",
+                weather: "Weather",
+            },
+            records: {
+                fruitNutrition: {
+                    name: "Fruit Retention Nutrition",
+                    effect: "Improves fruit quality and reduces drop",
+                },
+                shakeFlower: {
+                    name: "Flower Shaking",
+                    effect: "Prevents flower rot and promotes pollination",
+                },
+                killSmallLeaf: {
+                    name: "Small Leaf Removal",
+                    effect: "Promotes panicle growth",
+                },
+                strongFlowerNutrition: {
+                    name: "Flower Boost Nutrition",
+                    effect: "Develops strong panicles",
+                },
+                wakeNutrition: {
+                    name: "Bud Wake Nutrition",
+                    effect: "Promotes flower bud growth",
+                },
+                shootKill: {
+                    name: "Shoot Removal",
+                    effect: "Promotes flower bud differentiation",
+                },
+                clearGarden: {
+                    name: "Orchard Cleanup",
+                    effect: "Reduces pest and disease baseline",
+                },
+                baseFertilizer: {
+                    name: "Base Fertilizer",
+                    effect: "Provides year-round nutrition",
+                },
+                shootControl: {
+                    name: "Shoot Control",
+                    effect: "Reduces pest and disease baseline",
+                },
+                shootPestControl: {
+                    name: "Shoot Pest Control",
+                    effect: "Reduces pest risk",
+                },
+                shootNutrition: {
+                    name: "Shoot Nutrition",
+                    effect: "Reduces pest risk",
+                },
+                shootRootFertilizer: {
+                    name: "Shoot Root Fertilizer",
+                    effect: "Strengthens tree nutrition, promotes healthy new shoots and pest resistance",
+                },
+                fruitRootFertilizer: {
+                    name: "Fruit Root Fertilizer",
+                    effect: "Speeds fruit expansion and weight; reduces drop and cracking; improves uniformity and heat/rain resistance",
+                },
+                strongFlowerTopDress: {
+                    name: "Flower Top Dressing",
+                    effect: "Strengthens panicles and female flower ratio; improves cold/rain tolerance during bloom",
+                },
+                shootHeatDrought: {
+                    name: "Shoot Heat & Drought",
+                    effect: "Morning/evening canopy misting (avoid midday heat) to ease heat stress, promote even flush and root uptake",
+                },
+                fruitRainShade: {
+                    name: "Fruit Rain & Low Light",
+                    effect: "Foliar feeding to boost photosynthesis and nutrient transport for full, sweet, flavorful fruit",
+                },
+                flowerRain: {
+                    name: "Continuous Bloom Rain",
+                    effect: "Hand pollination or bees between rains; shake branches to drain panicles; protect pollen and control blight to restore fruit set",
+                },
+            },
+        },
+        adoptList: {
+            filters: {
+                allArea: "All Areas",
+                zone1: "Zone 1",
+                zone2: "Zone 2",
+                allCategory: "All Varieties",
+                jinggang: "Jinggang Hongnuo",
+                allAge: "All Ages",
+                ageRange1: "0-10 yrs",
+                ageRange2: "10-20 yrs",
+                allScore: "All Scores",
+                ecologyScore: "Ecology Score",
+                allStatus: "All Status",
+            },
+            placeholders: {
+                allArea: "All Areas",
+                allCategory: "All Varieties",
+                treeAge: "Tree Age",
+                overallScore: "Overall Score",
+                ecologyScore: "Ecology Score",
+                allStatus: "All Status",
+                selectSetting: "Select Setting",
+                input: "Enter value",
+            },
+            setting: "Set",
+            unpPriced: "Unpriced",
+            overall: "Overall:",
+            ecology: "Ecology:",
+            points: " pts",
+            unitPrice: "Unit Price: ",
+            treeAgeLabel: "Tree Age: ",
+            totalAdopt: "Total Adoption: ",
+            remaining: "Remaining: ",
+            owner: "Owner: ",
+            defaultAge: "5 yrs",
+            confirmEdit: "Confirm",
+            batchPricing: "Batch Pricing",
+            settingType: {
+                price: "Unit Price",
+                age: "Tree Age",
+                total: "Adoption Weight",
+            },
+            units: {
+                yuanPerJin: " CNY/jin",
+                year: " yrs",
+                jin: " jin",
+            },
+            ownerJin: "{name}({value} jin)",
+            progressRemain: "{current}/{total} jin",
+        },
+    },
+};

+ 5 - 1
src/main.js

@@ -26,6 +26,7 @@ import Print from 'vue3-print-nb'
 import vue3PhotoPreview from 'vue3-photo-preview'
 import 'vue3-photo-preview/dist/index.css'
 import 'vant/lib/index.css';
+import i18nPlugin from "@/plugins/i18n";
 
 const app = createApp(App);
 app.use(mock)
@@ -42,7 +43,10 @@ app.use(mock)
         fullscreen: true, // 是否启用全屏
         download: false, // 是否启用下载
         rotate: false, // 是否启用旋转
-      });
+      })
+    .use(i18nPlugin);
 
+document.documentElement.lang =
+    (localStorage.getItem("foster_pc_locale") || "zh") === "en" ? "en" : "zh-CN";
 
 app.mount("#app");

+ 9 - 0
src/plugins/i18n.js

@@ -0,0 +1,9 @@
+import { translate } from "@/i18n";
+import store from "@/store";
+
+export default {
+    install(app) {
+        app.config.globalProperties.$t = (key, params) =>
+            translate(key, params, store.state.locale?.locale || "zh");
+    },
+};

+ 29 - 0
src/store/modules/locale/index.js

@@ -0,0 +1,29 @@
+const LOCALE_KEY = "foster_pc_locale";
+
+export default {
+    namespaced: true,
+    state: {
+        locale: localStorage.getItem(LOCALE_KEY) || "zh",
+    },
+    mutations: {
+        SET_LOCALE(state, locale) {
+            state.locale = locale;
+            localStorage.setItem(LOCALE_KEY, locale);
+            document.documentElement.lang = locale === "en" ? "en" : "zh-CN";
+        },
+        TOGGLE_LOCALE(state) {
+            const next = state.locale === "zh" ? "en" : "zh";
+            state.locale = next;
+            localStorage.setItem(LOCALE_KEY, next);
+            document.documentElement.lang = next === "en" ? "en" : "zh-CN";
+        },
+    },
+    actions: {
+        toggleLocale({ commit }) {
+            commit("TOGGLE_LOCALE");
+        },
+        setLocale({ commit }, locale) {
+            commit("SET_LOCALE", locale);
+        },
+    },
+};

+ 129 - 102
src/views/home/components/adoptList.vue

@@ -1,110 +1,123 @@
 <template>
     <div class="adopt-list" :class="{ 'has-btn': isManySetting }">
         <div class="select-wrap">
-            <el-select class="select-item" v-model="areaVal" placeholder="全区" style="width: 116px">
+            <el-select class="select-item" v-model="areaVal" :placeholder="t('adoptList.placeholders.allArea')" style="width: 116px">
                 <el-option v-for="item in areaOptions" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
-            <el-select class="select-item" v-model="typeVal" placeholder="全部品类" style="width: 116px">
+            <el-select class="select-item" v-model="typeVal" :placeholder="t('adoptList.placeholders.allCategory')" style="width: 116px">
                 <el-option v-for="item in typeOptions" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
-            <el-select class="select-item" v-model="ageVal" placeholder="树龄" style="width: 116px">
+            <el-select class="select-item" v-model="ageVal" :placeholder="t('adoptList.placeholders.treeAge')" style="width: 116px">
                 <el-option v-for="item in ageOptions" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
         </div>
         <div class="select-wrap select-b">
-            <el-select class="select-item" v-model="allVal" placeholder="综合评分" style="width: 116px">
+            <el-select class="select-item" v-model="allVal" :placeholder="t('adoptList.placeholders.overallScore')" style="width: 116px">
                 <el-option v-for="item in allOptions" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
-            <el-select class="select-item" v-model="ecologyVal" placeholder="生态评分" style="width: 116px">
+            <el-select class="select-item" v-model="ecologyVal" :placeholder="t('adoptList.placeholders.ecologyScore')" style="width: 116px">
                 <el-option v-for="item in ecologyOptions" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
-            <el-select class="select-item" v-model="statusVal" placeholder="全部状态" style="width: 116px">
+            <el-select class="select-item" v-model="statusVal" :placeholder="t('adoptList.placeholders.allStatus')" style="width: 116px">
                 <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
         </div>
 
         <div class="many-setting select-wrap" v-show="isManySetting">
-            <el-select class="select-item many-select" v-model="settingType" placeholder="选中设置项" style="width: 96px">
+            <el-select class="select-item many-select" v-model="settingType" :placeholder="t('adoptList.placeholders.selectSetting')" style="width: 96px">
                 <template #label="{ label, value }">
-                    <span v-show="value!=='total'">设置</span>
+                    <span v-show="value !== 'total'">{{ t('adoptList.setting') }}</span>
                     <span>{{ label }}</span>
                 </template>
                 <el-option v-for="(item, index) in settingTypeOptions" :key="index" :label="item.name" :value="item.value" />
             </el-select>
             <el-input-number
                 style="width: 174px"
-                placeholder="请输入"
+                :placeholder="t('adoptList.placeholders.input')"
                 class="number-input"
                 :controls="false"
                 v-model="unifyPrice"
                 :min="0"
                 @change="setManyPrice"
             />
-            <span class="unit">{{settingType === "price" ? "元/斤" : settingType === "age" ? "年" : "斤"}}</span>
+            <span class="unit">{{ settingUnit }}</span>
         </div>
 
         <div class="list-wrap">
             <div class="list-item" v-for="(item, index) in displayedAdoptList" :key="index">
                 <div class="list-info">
                     <div class="tree-icon">
-                        <div class="tree-tag" v-show="item.status === 0">{{ ROLE == 1 ? "未定价" : "可团购"}}</div>
-                        <div class="tree-tag wait" v-show="item.status === 1">{{ ROLE == 1 ? "待认养" : "可团购"}}</div>
-                        <div class="tree-tag done" v-show="item.status === 2">{{ ROLE == 1 ? "已认养" : "已认养"}}</div>
-                        <!-- <img class="tree-img" src="@/assets/images/foster-home/tree-item.png" alt="" /> -->
+                        <div class="tree-tag" v-show="item.status === 0">
+                            {{ ROLE == 1 ? t('adoptList.unpPriced') : t('home.legend.groupBuy') }}
+                        </div>
+                        <div class="tree-tag wait" v-show="item.status === 1">
+                            {{ ROLE == 1 ? t('home.legend.pending') : t('home.legend.groupBuy') }}
+                        </div>
+                        <div class="tree-tag done" v-show="item.status === 2">{{ t('home.legend.adopted') }}</div>
                         <img class="tree-img" :src="require(`@/assets/images/foster-home/list/${index < 7 ? index : 0}.png`)" alt="" />
-                        <div class="tree-type-name-tag">白糖罂</div>
+                        <div class="tree-type-name-tag">{{ t('gardenIntroduce.cropType') }}</div>
                     </div>
                     <div class="item-center">
                         <div class="center-t">
-                            {{item.bm ? item.bm : "BTY-A3"+index}}
-                            <span class="type-tag">综合:{{item.zh||94}}分</span>
-                            <span class="type-tag">生态:{{item.st||92}}分</span>
+                            {{ item.bm ? item.bm : "BTY-A3" + index }}
+                            <span class="type-tag">{{ t('adoptList.overall') }}{{ item.zh || 94 }}{{ t('adoptList.points') }}</span>
+                            <span class="type-tag">{{ t('adoptList.ecology') }}{{ item.st || 92 }}{{ t('adoptList.points') }}</span>
                         </div>
-                        <!-- 批量设置单价 -->
-                        <div class="center-item" v-show="isManySetting && settingType !== 'price'">单价:<span class="unit">{{item.price||12}}元/斤</span></div>
-                        
-                        <!-- 批量设置树龄或单项设置 -->
+                        <div class="center-item" v-show="isManySetting && settingType !== 'price'">
+                            {{ t('adoptList.unitPrice') }}<span class="unit">{{ item.price || 12 }}{{ t('adoptList.units.yuanPerJin') }}</span>
+                        </div>
+
                         <div class="center-item p-t-2 has-input" v-show="(isManySetting && settingType === 'age') || item.settingPrice">
-                            <span class="edit-label">树龄:</span>
+                            <span class="edit-label">{{ t('adoptList.treeAgeLabel') }}</span>
                             <el-input-number @change="settingSinglePrice" class="number-input" :controls="false" v-model="item.age" :min="0" />
-                            <span class="unit"></span>
+                            <span class="unit">{{ t('adoptList.units.year') }}</span>
                         </div>
-                        <!-- 不是编辑状态 -->
                         <div class="center-item p-t-2 age-line" v-show="!isManySetting && !item.settingPrice">
                             <div class="age-wrap">
                                 <div class="has-age">
-                                    <div class="age">树龄:<span class="unit">5年</span></div>
+                                    <div class="age">
+                                        {{ t('adoptList.treeAgeLabel') }}<span class="unit">{{ t('adoptList.defaultAge') }}</span>
+                                    </div>
                                 </div>
                                 <div class="sort-line"></div>
                             </div>
-                            单价:<span class="unit">{{item.status === 0 ? "--" : item.price||12}}元/斤</span>
+                            {{ t('adoptList.unitPrice') }}<span class="unit">{{ item.status === 0 ? "--" : item.price || 12 }}{{ t('adoptList.units.yuanPerJin') }}</span>
                         </div>
                         <div class="center-item p-t-2 has-input" v-show="(isManySetting && settingType === 'price') || item.settingPrice">
-                            <span class="edit-label">单价:</span>
+                            <span class="edit-label">{{ t('adoptList.unitPrice') }}</span>
                             <el-input-number @change="settingSinglePrice" class="number-input" :controls="false" v-model="item.price" :min="0" />
-                            <span class="unit">元/斤</span>
+                            <span class="unit">{{ t('adoptList.units.yuanPerJin') }}</span>
+                        </div>
+                        <div class="center-item" v-show="isManySetting && settingType !== 'age'">
+                            {{ t('adoptList.treeAgeLabel') }}<span class="unit">{{ item.age || 5 }}{{ t('adoptList.units.year') }}</span>
+                        </div>
+                        <div class="center-item" v-show="!item.settingPrice && !isManySetting && ROLE == 1">
+                            {{ t('adoptList.totalAdopt') }}<span class="unit">{{ item.total || 212 }}{{ t('adoptList.units.jin') }}</span>
                         </div>
-                        <div class="center-item" v-show="isManySetting && settingType !== 'age'">树龄:<span class="unit">{{item.age||5}}年</span></div>
-                        <div class="center-item" v-show="!item.settingPrice && !isManySetting && ROLE == 1">总认养斤数:<span class="unit">{{item.total||212}}斤</span></div>
-                        <div class="center-item" v-show="(isManySetting && settingType !== 'total' && ROLE == 1)">总认养斤数:<span class="unit">{{item.total||212}}斤</span></div>
-                        
+                        <div class="center-item" v-show="isManySetting && settingType !== 'total' && ROLE == 1">
+                            {{ t('adoptList.totalAdopt') }}<span class="unit">{{ item.total || 212 }}{{ t('adoptList.units.jin') }}</span>
+                        </div>
+
                         <div class="center-item p-t-2 has-input" v-show="(isManySetting && settingType === 'total') || item.settingPrice">
-                            <span class="edit-label">总认养斤数:</span>
+                            <span class="edit-label">{{ t('adoptList.totalAdopt') }}</span>
                             <el-input-number @change="settingSinglePrice" class="number-input" :controls="false" v-model="item.total" :min="0" />
-                            <span class="unit"></span>
+                            <span class="unit">{{ t('adoptList.units.jin') }}</span>
                         </div>
-                        <!-- 团长角色 -->
-                        <div class="center-item p-t-2 progress-wrap" v-show="ROLE==2 && item.status !== 2">
-                            剩余可购:
-                            <el-progress :percentage="60" color="#FFD887"><span class="progress-text"><span class="over">150</span>/215斤</span></el-progress>
+                        <div class="center-item p-t-2 progress-wrap" v-show="ROLE == 2 && item.status !== 2">
+                            {{ t('adoptList.remaining') }}
+                            <el-progress :percentage="60" color="#FFD887">
+                                <span class="progress-text">
+                                    <span class="over">150</span>/215{{ t('adoptList.units.jin') }}
+                                </span>
+                            </el-progress>
                         </div>
-                        <div class="center-item p-t-2 progress-wrap" v-show="ROLE==2 && item.status === 2">
-                            权属人:
+                        <div class="center-item p-t-2 progress-wrap" v-show="ROLE == 2 && item.status === 2">
+                            {{ t('adoptList.owner') }}
                             <span class="unit">
                                 <div class="user-item">
                                     <div class="user-detail" v-for="(owner, oI) in owners" :key="oI">
-                                        {{ owner.userName }}({{ owner.value }}斤)
-                                        <span v-show="oI<owners.length-1">/</span>
+                                        {{ formatOwner(owner) }}
+                                        <span v-show="oI < owners.length - 1">/</span>
                                     </div>
                                 </div>
                             </span>
@@ -115,67 +128,88 @@
                     </div>
                 </div>
                 <div v-show="item.settingPrice" class="btn-group edit-one">
-                    <!-- 渐变主色按钮 -->
-                    <div class="btn cancel-btn" @click="toSettingSinglePrice(index, false)">取消</div>
-                    <div class="btn edit-btn" @click="toSettingSinglePrice(index, false)">确认修改</div>
+                    <div class="btn cancel-btn" @click="toSettingSinglePrice(index, false)">{{ t('home.cancel') }}</div>
+                    <div class="btn edit-btn" @click="toSettingSinglePrice(index, false)">{{ t('adoptList.confirmEdit') }}</div>
                 </div>
             </div>
         </div>
 
-        <!-- 渐变主色按钮 -->
-        <div class="center-btn" v-show="!isManySetting" @click="manySetPrice">批量定价</div>
-        <!-- 渐变主色按钮 -->
+        <div class="center-btn" v-show="!isManySetting" @click="manySetPrice">{{ t('adoptList.batchPricing') }}</div>
         <div class="btn-group list-btn" v-show="isManySetting">
-            <div class="btn cancel-btn" @click="saveManySetting(0)">取消</div>
-            <div class="btn edit-btn" @click="saveManySetting(1)">保存</div>
+            <div class="btn cancel-btn" @click="saveManySetting(0)">{{ t('home.cancel') }}</div>
+            <div class="btn edit-btn" @click="saveManySetting(1)">{{ t('gardenIntroduce.save') }}</div>
         </div>
     </div>
 </template>
 
 <script setup>
-import { onMounted, ref } from "vue";
+import { computed, onMounted, ref } from "vue";
 import { useStore } from "vuex";
-let store = useStore();
+import { useI18n } from "@/i18n";
 
+const { t } = useI18n();
+const store = useStore();
 const ROLE = store.state.home.userRole;
 
+const ageRangeOptions = computed(() => [
+    { label: t("adoptList.filters.ageRange1"), value: 1 },
+    { label: t("adoptList.filters.ageRange2"), value: 2 },
+]);
+
 const areaVal = ref(0);
-const areaOptions = ref([
-    { label: "全区", value: 0 },
-    { label: "1区", value: 1 },
-    { label: "2区", value: 2 },
+const areaOptions = computed(() => [
+    { label: t("adoptList.filters.allArea"), value: 0 },
+    { label: t("adoptList.filters.zone1"), value: 1 },
+    { label: t("adoptList.filters.zone2"), value: 2 },
 ]);
+
 const typeVal = ref(0);
-const typeOptions = ref([
-    { label: "全部品类", value: 0 },
-    { label: "白糖罂", value: 1 },
-    { label: "井岗红糯", value: 2 },
+const typeOptions = computed(() => [
+    { label: t("adoptList.filters.allCategory"), value: 0 },
+    { label: t("gardenIntroduce.cropType"), value: 1 },
+    { label: t("adoptList.filters.jinggang"), value: 2 },
 ]);
+
 const ageVal = ref(0);
-const ageOptions = ref([
-    { label: "全部树龄", value: 0 },
-    { label: "0-10年", value: 1 },
-    { label: "10-20年", value: 2 },
+const ageOptions = computed(() => [
+    { label: t("adoptList.filters.allAge"), value: 0 },
+    ...ageRangeOptions.value,
 ]);
+
 const allVal = ref(0);
-const allOptions = ref([
-    { label: "全部评分", value: 0 },
-    { label: "0-10年", value: 1 },
-    { label: "10-20年", value: 2 },
+const allOptions = computed(() => [
+    { label: t("adoptList.filters.allScore"), value: 0 },
+    ...ageRangeOptions.value,
 ]);
+
 const ecologyVal = ref(0);
-const ecologyOptions = ref([
-    { label: "生态评分", value: 0 },
-    { label: "0-10年", value: 1 },
-    { label: "10-20年", value: 2 },
+const ecologyOptions = computed(() => [
+    { label: t("adoptList.filters.ecologyScore"), value: 0 },
+    ...ageRangeOptions.value,
 ]);
+
 const statusVal = ref(0);
-const statusOptions = ref([
-    { label: "全部状态", value: 0 },
-    { label: "0-10年", value: 1 },
-    { label: "10-20年", value: 2 },
+const statusOptions = computed(() => [
+    { label: t("adoptList.filters.allStatus"), value: 0 },
+    ...ageRangeOptions.value,
 ]);
 
+const settingUnit = computed(() => {
+    if (settingType.value === "price") return t("adoptList.units.yuanPerJin");
+    if (settingType.value === "age") return t("adoptList.units.year");
+    return t("adoptList.units.jin");
+});
+
+const settingTypeOptions = computed(() => [
+    { name: t("adoptList.settingType.price"), value: "price" },
+    { name: t("adoptList.settingType.age"), value: "age" },
+    { name: t("adoptList.settingType.total"), value: "total" },
+]);
+
+function formatOwner(owner) {
+    return t("adoptList.ownerJin", { name: owner.userName, value: owner.value });
+}
+
 const adoptList = ref([
     { status: 0, price: 10, bm: "BTY-A21", pz: "白糖罂", zh: 94, st: 92, sl: 5, total: 215 },
     { status: 0, price: 12, bm: "BTY-A22", pz: "白糖罂", zh: 92, st: 94, sl: 6, total: 201 },
@@ -188,45 +222,42 @@ const adoptList = ref([
     { status: 2, price: 16 },
 ]);
 
-const owners = ref([{userName: "王丽丽", value: 50}, {userName: "张山", value: 30}])
+const owners = ref([
+    { userName: "王丽丽", value: 50 },
+    { userName: "张山", value: 30 },
+]);
 
-const displayedAdoptList = ref([...adoptList.value]); // 初始时显示完整列表
+const displayedAdoptList = ref([...adoptList.value]);
 
 onMounted(() => {});
 
-// 批量定价
 const unifyPrice = ref(null);
 const isManySetting = ref(false);
-const settingTypeOptions = [
-    {name: "单价", value: "price"},
-    {name: "树龄", value: "age"},
-    {name: "认养斤数", value: "total"},
-]
-const settingType = ref("price")
+const settingType = ref("price");
+
 function manySetPrice() {
     isManySetting.value = true;
     displayedAdoptList.value = adoptList.value.filter((item) => item.status === 0);
 }
+
 function saveManySetting(isToSave) {
     isManySetting.value = false;
-    displayedAdoptList.value = [...adoptList.value]; // 显示完整列表
+    displayedAdoptList.value = [...adoptList.value];
     if (isToSave) {
         // 保存
     }
 }
 
 function setManyPrice(v) {
-  displayedAdoptList.value.map(item => item.price = v)
+    displayedAdoptList.value.map((item) => (item.price = v));
 }
 
-// 设置单棵树单价
-
 function toSettingSinglePrice(i, val) {
-  console.log('tototot');
-  displayedAdoptList.value[i].settingPrice = val
+    displayedAdoptList.value[i].settingPrice = val;
 }
+
 function settingSinglePrice() {
-  console.log('sss');
+    // 单项设置保存
 }
 </script>
 
@@ -294,7 +325,7 @@ function settingSinglePrice() {
                         padding: 5px;
                         &.cancel-btn {
                             border-color: #363636;
-                            color: #FFFFFF;
+                            color: #ffffff;
                         }
                     }
                 }
@@ -346,10 +377,10 @@ function settingSinglePrice() {
                 }
                 .center-item {
                     color: #6c6c6c;
-                    font-size: 12px;
+                    font-size: 11px;
                     padding-top: 2px;
                 }
-                
+
                 .progress-wrap {
                     display: flex;
                     align-items: center;
@@ -361,7 +392,7 @@ function settingSinglePrice() {
                         font-size: 12px;
                         color: #999999;
                         .over {
-                            color: #FFD489;
+                            color: #ffd489;
                         }
                     }
                     ::v-deep {
@@ -381,7 +412,7 @@ function settingSinglePrice() {
                             margin: 0 10px;
                             height: 10px;
                             width: 1px;
-                            background: #6C6C6C;
+                            background: #6c6c6c;
                         }
                     }
                 }
@@ -395,10 +426,6 @@ function settingSinglePrice() {
                         padding-left: 5px;
                     }
                 }
-                .small-btn-group {
-                  display: flex;
-                  font-size: 12px;
-                }
             }
         }
         .list-item + .list-item {

+ 43 - 34
src/views/home/components/gardenIntroduce.vue

@@ -5,49 +5,53 @@
                 <img class="garden-img" src="@/assets/images/foster-home/garden-img.png" alt="" />
                 <div class="overview-info">
                     <div class="garden-name">
-                        柏桥村
-                        <span class="type-tag">白糖罂</span>
+                        {{ t('gardenIntroduce.gardenName') }}
+                        <span class="type-tag">{{ t('gardenIntroduce.cropType') }}</span>
+                    </div>
+                    <div class="info-item center-info">
+                        {{ t('gardenIntroduce.areaLabel') }}<span class="info-val">{{ t('gardenIntroduce.areaValue') }}</span>
+                    </div>
+                    <div class="info-item">
+                        {{ t('gardenIntroduce.addressLabel') }}<span class="info-val">{{ t('gardenIntroduce.addressValue') }}</span>
                     </div>
-                    <div class="info-item center-info">果园面积:<span class="info-val">6800亩</span></div>
-                    <div class="info-item">果园地址:<span class="info-val">广东省茂名市高州市根子镇下辖村</span></div>
                 </div>
             </div>
 
             <div class="overview-data-box">
                 <div class="box-item">
                     <div class="item-val">383<span>/1001</span></div>
-                    <div class="item-name">已认养(棵)</div>
+                    <div class="item-name">{{ t('gardenIntroduce.adoptedCount') }}</div>
                 </div>
                 <div class="box-item">
                     <div class="item-val">96</div>
-                    <div class="item-name">综合评分(分)</div>
+                    <div class="item-name">{{ t('gardenIntroduce.overallScore') }}</div>
                 </div>
                 <div class="box-item">
                     <div class="item-val">98</div>
-                    <div class="item-name">生态评分(分)</div>
+                    <div class="item-name">{{ t('gardenIntroduce.ecologyScore') }}</div>
                 </div>
             </div>
         </div>
 
         <div class="sub-box">
-            <sub-title name="果园简介">
+            <sub-title :name="t('gardenIntroduce.introTitle')">
                 <template v-slot:title-right>
                     <div class="title-right" @click="editDesc" v-show="!isEdit">
                         <img class="sub-edit" src="@/assets/images/common/edit-icon.png" alt="" />
-                        编辑
+                        {{ t('gardenIntroduce.edit') }}
                     </div>
                     <div class="title-right-btn" v-show="isEdit">
-                        <div class="btn cancel-btn" @click="isEdit = false">取消</div>
-                        <div class="btn edit-btn" @click="saveDesc">保存</div>
+                        <div class="btn cancel-btn" @click="cancelEdit">{{ t('home.cancel') }}</div>
+                        <div class="btn edit-btn" @click="saveDesc">{{ t('gardenIntroduce.save') }}</div>
                     </div>
                 </template>
             </sub-title>
             <div class="sub-content">
                 <div class="content-text" v-show="isEdit">
-                    <el-input v-model="gardenDes" :autosize="{ minRows: 2, maxRows: 8 }" type="textarea" />
+                    <el-input v-model="editBuffer" :autosize="{ minRows: 2, maxRows: 8 }" type="textarea" />
                 </div>
                 <div class="content-text" v-show="!isEdit">
-                    {{ gardenDes }}
+                    {{ displayDes }}
                 </div>
             </div>
         </div>
@@ -55,34 +59,34 @@
         <div class="sub-box">
             <div class="honour-name">
                 <img class="honour-l" src="@/assets/images/foster-home/honour-bg.png" alt="" />
-                勋章墙
+                {{ t('gardenIntroduce.medalWall') }}
                 <img class="honour-r" src="@/assets/images/foster-home/honour-bg.png" alt="" />
                 <div class="honour-more title-right" @click="handleMore('medal')">
-                    更多
+                    {{ t('gardenIntroduce.more') }}
                     <el-icon class="sub-icon"><ArrowRight /></el-icon>
                 </div>
             </div>
             <div class="honour-imgs">
                 <div class="honour-item">
                     <img src="@/assets/images/foster-home/water-icon.png" alt="" />
-                    <div class="icon-name">水源洁净</div>
+                    <div class="icon-name">{{ t('gardenIntroduce.honourWater') }}</div>
                 </div>
                 <div class="honour-item">
                     <img src="@/assets/images/foster-home/wind-icon.png" alt="" />
-                    <div class="icon-name">风畅气顺</div>
+                    <div class="icon-name">{{ t('nav.windFlow') }}</div>
                 </div>
                 <div class="honour-item">
                     <img src="@/assets/images/foster-home/tree-icon.png" alt="" />
-                    <div class="icon-name">古树名木</div>
+                    <div class="icon-name">{{ t('nav.ancientTrees') }}</div>
                 </div>
             </div>
         </div>
 
         <div class="sub-box">
-            <sub-title name="美景视频">
+            <sub-title :name="t('gardenIntroduce.scenicVideo')">
                 <template v-slot:title-right>
                     <div class="title-right" @click="handleMore('video')">
-                        更多
+                        {{ t('gardenIntroduce.more') }}
                         <el-icon class="sub-icon"><ArrowRight /></el-icon>
                     </div>
                 </template>
@@ -93,10 +97,10 @@
         </div>
 
         <div class="sub-box">
-            <sub-title name="农事记录">
+            <sub-title :name="t('gardenIntroduce.farmRecord')">
                 <template v-slot:title-right>
                     <div class="title-right" @click="handleMore('record')">
-                        更多
+                        {{ t('gardenIntroduce.more') }}
                         <el-icon class="sub-icon"><ArrowRight /></el-icon>
                     </div>
                 </template>
@@ -115,35 +119,40 @@
 </template>
 
 <script setup>
-import { onMounted, ref } from "vue";
+import { computed, ref } from "vue";
 import subTitle from "@/components/subTitle.vue";
 import { Popup } from "vant";
-import eventBus from "@/api/eventBus";
 import { useRouter } from "vue-router";
+import { useI18n } from "@/i18n";
+
+const { t } = useI18n();
 const router = useRouter();
 
-// 简介
 const isEdit = ref(false);
-const gardenDes = ref(
-    "柏桥村位于广东茂名高州根子镇,是千年荔枝之乡的核心产区,盛产果肉晶莹、鲜甜多汁的白糖罂荔枝。村内6800亩荔枝林与古荔园中48棵百年以上古树交相辉映,诉说着种植传奇。依托冷链物流和电商直播,新鲜荔枝一键直达全国。"
-);
+const editBuffer = ref("");
+const savedDes = ref(null);
+
+const displayDes = computed(() => savedDes.value ?? t("gardenIntroduce.description"));
+
 function editDesc() {
+    editBuffer.value = displayDes.value;
     isEdit.value = true;
 }
 
-//更多
-const handleMore = (url) =>{
-    router.push(`/more_${url}`)
+function cancelEdit() {
+    isEdit.value = false;
 }
 
 function saveDesc() {
-    // 保存
+    savedDes.value = editBuffer.value;
     isEdit.value = false;
 }
 
-const showPopup = ref(false);
+const handleMore = (url) => {
+    router.push(`/more_${url}`);
+};
 
-onMounted(() => {});
+const showPopup = ref(false);
 
 function showVideo() {
     showPopup.value = true;

+ 4 - 1
src/views/home/components/homePage.vue

@@ -1,7 +1,7 @@
 <template>
     <div class="chart-list">
         <div class="chart-item weather-item">
-            <chart-box name="果园介绍">
+            <chart-box :name="t('home.gardenIntro')">
                 <garden-introduce></garden-introduce>
             </chart-box>
         </div>
@@ -19,6 +19,9 @@ import eventBus from "@/api/eventBus";
 import { useStore } from "vuex";
 import { useRouter } from "vue-router";
 import gardenIntroduce from "../components/gardenIntroduce.vue";
+import { useI18n } from "@/i18n";
+
+const { t } = useI18n();
 const store = useStore();
 const router = useRouter();
 

+ 79 - 185
src/views/home/components/treeDetail.vue

@@ -1,35 +1,35 @@
 <template>
     <div class="detail-page">
-        <chart-box name="果树介绍" arrow="">
+        <chart-box :name="t('treeDetail.title')" arrow="">
             <template v-slot:title-right>
-                <div class="back" @click="backToHome">返回</div>
+                <div class="back" @click="backToHome">{{ t('treeDetail.back') }}</div>
             </template>
             <div class="detail-content">
                 <div class="detail-main">
                     <div class="bubble-box">
                         <div class="bubble old">
-                            <span>10年</span>
-                            <div>树龄</div>
+                            <span>{{ t('treeDetail.treeAgeValue') }}</span>
+                            <div>{{ t('treeDetail.treeAge') }}</div>
                         </div>
                         <div class="bubble pz">
-                            <span>白糖罂</span>
-                            <div>品种</div>
+                            <span>{{ t('gardenIntroduce.cropType') }}</span>
+                            <div>{{ t('treeDetail.variety') }}</div>
                         </div>
                         <div class="bubble code">
                             <span>A1158</span>
-                            <div>唯一编码</div>
+                            <div>{{ t('treeDetail.uniqueCode') }}</div>
                         </div>
                         <div class="bubble cl big">
-                            <span>150斤</span>
-                            <div>高质产量</div>
+                            <span>{{ t('treeDetail.highYieldValue') }}</span>
+                            <div>{{ t('treeDetail.highYield') }}</div>
                         </div>
                         <div class="bubble date big">
                             <span>2025.06.08</span>
-                            <div>上市时间</div>
+                            <div>{{ t('treeDetail.marketDate') }}</div>
                         </div>
                         <div class="bubble zb big">
-                            <span>92分</span>
-                            <div>生态指标</div>
+                            <span>92{{ locale === 'zh' ? '' : ' pts' }}</span>
+                            <div>{{ t('treeDetail.ecologyIndex') }}</div>
                         </div>
 
                         <div class="progress-wrap" v-show="ROLE == 2 && isProgress === 1">
@@ -37,19 +37,17 @@
                             <el-progress class="progress-val" :percentage="60" color="#FFD887"></el-progress>
                         </div>
                         <div class="progress-wrap done-progress" v-show="ROLE == 2 && isProgress === 0">
-                            <div class="progress-text">团购/认养已结束</div>
+                            <div class="progress-text">{{ t('treeDetail.progressEnded') }}</div>
                         </div>
                     </div>
                     <img class="tree" src="@/assets/images/foster-home/tree.png" alt="" />
                     <div class="photo-box">
                         <div class="photo-title">
-                            <span>溯源照片</span>
-                            <span class="more" @click="handleMore">更多></span>
+                            <span>{{ t('treeDetail.tracePhotos') }}</span>
+                            <span class="more" @click="handleMore">{{ t('treeDetail.more') }}</span>
                         </div>
                         <div class="photo-list">
                             <div class="photo-item" v-for="(item, index) in photoList" :key="index">
-                                <!-- photo-img-2.JPG -->
-                                <!-- <img class="img" :src="require(`@/assets/images/foster-home/tree/photo-img-${1}.JPG`)" alt="" /> -->
                                 <photo-provider>
                                     <photo-consumer
                                         :src="require(`@/assets/images/foster-home/tree/photo-img-${index}.jpeg`)"
@@ -61,7 +59,6 @@
                                         />
                                     </photo-consumer>
                                 </photo-provider>
-
                                 <div class="date">{{ item.date }}</div>
                             </div>
                         </div>
@@ -69,10 +66,10 @@
                 </div>
                 <div class="source-wrap">
                     <div class="source-title">
-                        <sub-title name="农事记录">
+                        <sub-title :name="t('gardenIntroduce.farmRecord')">
                             <template v-slot:title-right>
                                 <div class="title-right">
-                                    更多
+                                    {{ t('gardenIntroduce.more') }}
                                     <el-icon class="sub-icon"><ArrowRight /></el-icon>
                                 </div>
                             </template>
@@ -89,7 +86,7 @@
                             {{ item }}
                         </div>
                     </div>
-                    <div class="list-item" v-for="(ele, idx) in sourceList" :key="idx">
+                    <div class="list-item" v-for="(ele, idx) in displaySourceList" :key="idx">
                         <div class="item-flex">
                             <div class="photo">
                                 <img src="@/assets/images/foster-home/tree/source.png" alt="" />
@@ -97,44 +94,83 @@
                             </div>
                             <div class="item-text">
                                 <div class="item-title">{{ ele.name }}</div>
-                                <!-- <div class="name">
-                                    触发原因:<span class="val">{{ ele.reason }}</span>
-                                </div> -->
                                 <div class="name">
-                                    农事效果:<span class="val">{{ ele.effect }}</span>
+                                    {{ t('treeDetail.farmEffect') }}<span class="val">{{ ele.effect }}</span>
                                 </div>
                             </div>
                         </div>
                     </div>
                 </div>
-                <!-- 渐变主色按钮 -->
-                <div class="center-btn" @click="toCustomPage">我要定制</div>
+                <div class="center-btn" @click="toCustomPage">{{ t('treeDetail.customBtn') }}</div>
             </div>
         </chart-box>
     </div>
 </template>
 
 <script setup>
-import { ref } from "vue";
+import { computed, ref } from "vue";
 import { useRouter } from "vue-router";
+import { useStore } from "vuex";
 import chartBox from "@/components/chartBox.vue";
 import subTitle from "@/components/subTitle.vue";
+import { useI18n } from "@/i18n";
+
+const { t, locale } = useI18n();
 const router = useRouter();
-import { useStore } from "vuex";
-let store = useStore();
+const store = useStore();
 
 const ROLE = store.state.home.userRole;
-// 认养进度-1以结束/0进行中
 const isProgress = ref(1);
 
 const active = ref(0);
-const tabsList = ["全部", "标准", "气象"];
+const tabsList = computed(() => [
+    t("treeDetail.tabs.all"),
+    t("treeDetail.tabs.standard"),
+    t("treeDetail.tabs.weather"),
+]);
+
+const emit = defineEmits(["backHome"]);
+
+function translateRecord(record) {
+    return {
+        name: t(`treeDetail.records.${record.id}.name`),
+        effect: t(`treeDetail.records.${record.id}.effect`),
+        date: record.date,
+    };
+}
+
+const MAIN_RECORDS = [
+    { id: "fruitNutrition", date: "2025.04.04" },
+    { id: "shakeFlower", date: "2025.03.28" },
+    { id: "killSmallLeaf", date: "2025.02.09" },
+    { id: "strongFlowerNutrition", date: "2025.02.03" },
+    { id: "wakeNutrition", date: "2025.01.03" },
+    { id: "shootKill", date: "2024.12.27" },
+    { id: "clearGarden", date: "2024.12.15" },
+    { id: "baseFertilizer", date: "2024.12.15" },
+    { id: "shootControl", date: "2024.12.03" },
+    { id: "shootPestControl", date: "2024.08.15" },
+    { id: "shootNutrition", date: "2024.08.01" },
+];
+
+const ALT_RECORDS = [
+    { id: "shootRootFertilizer", date: "2024.07.14" },
+    { id: "fruitRootFertilizer", date: "2024.05.07" },
+    { id: "strongFlowerTopDress", date: "2024.03.07" },
+    { id: "shootHeatDrought", date: "2024.10.26" },
+    { id: "fruitRainShade", date: "2024.05.24" },
+    { id: "flowerRain", date: "2024.04.01" },
+];
+
+const currentRecords = ref([...MAIN_RECORDS]);
+
+const displaySourceList = computed(() => currentRecords.value.map(translateRecord));
+
 const handleActive = (index) => {
     active.value = index;
     handleItem(index);
 };
 
-const emit = defineEmits(["backHome"]);
 function backToHome() {
     emit("backHome");
 }
@@ -144,140 +180,20 @@ function toCustomPage() {
 }
 
 const photoList = ref([
-    {
-        date: "2025.04.10",
-    },
-    {
-        date: "2025.04.03",
-    },
-    {
-        date: "2025.03.26",
-    },
-    {
-        date: "2025.03.15",
-    },
-    {
-        date: "2025.03.08",
-    },
-]);
-
-const sourceList1 = ref([
-    {
-        name: "梢期根肥",
-        reason: "梢期需需要营养时机",
-        effect: "增强树体营养,促进新梢健壮,增强病虫抗性",
-        date: "2024.07.14",
-    },
-    {
-        name: "壮果根肥",
-        reason: "果期要营养时机",
-        effect: "促进果实快速膨大,提升单果重;减少生理落果与裂果,改善果实均匀度;增强抗高温/暴雨能力",
-        date: "2024.05.07",
-    },
-    {
-        name: "壮花追肥",
-        reason: "花期需要营养时机",
-        effect: "促进花穗健壮,提高雌花比例;增强花期抗低温/阴雨能力",
-        date: "2024.03.07",
-    },
-    {
-        name: "梢期高温干旱",
-        reason: "梢期需需要营养时机",
-        effect: "每日早晚树冠喷水降温(避开正午高温),以缓解高温抑制新梢生长,促进新梢抽发整齐、根系吸水效率提升",
-        date: "2024.10.26",
-    },
-    {
-        name: "果期阴雨寡照",
-        reason: "果期要营养时机",
-        effect: "补充叶面肥,增强光合作用,促进养分转运,避免光照不足影响,确保果实饱满、甜度高、风味佳",
-        date: "2024.05.24",
-    },
-    {
-        name: "花期连续阴雨",
-        reason: "花期需要营养时机",
-        effect: "雨停间隙人工施粉或放蜂授粉,轻摇树枝排出花穗积水,防止雨水冲刷花粉和霜疫霉病蔓延,确保坐果率恢复",
-        date: "2024.04.01",
-    },
-]);
-
-const sourceList = ref([
-    {
-        name: "保果营养",
-        reason: "梢期需需要营养时机",
-        effect: "提高果实质量,减少落果",
-        date: "2025.04.04",
-    },
-    {
-        name: "摇花吹花",
-        reason: "果期要营养时机",
-        effect: "防止沤花,促进授粉",
-        date: "2025.03.28",
-    },
-    {
-        name: "杀除小叶",
-        reason: "花期需要营养时机",
-        effect: "促进花穗生长",
-        date: "2025.02.09",
-    },
-    {
-        name: "壮花营养",
-        reason: "梢期需需要营养时机",
-        effect: "培养健壮花穗",
-        date: "2025.02.03",
-    },
-    {
-        name: "催醒营养",
-        reason: "果期要营养时机",
-        effect: "促进花芽生长",
-        date: "2025.01.03",
-    },
-    {
-        name: "杀梢",
-        reason: "花期需要营养时机",
-        effect: "促进花芽分化",
-        date: "2024.12.27",
-    },
-    {
-        name: "清园",
-        reason: "花期需要营养时机",
-        effect: "减少病虫害基数",
-        date: "2024.12.15",
-    },
-    {
-        name: "基肥",
-        reason: "花期需要营养时机",
-        effect: "提供全年营养",
-        date: "2024.12.15",
-    },
-    {
-        name: "控梢",
-        reason: "花期需要营养时机",
-        effect: "减少病虫害基数",
-        date: "2024.12.03",
-    },
-    {
-        name: "梢期防虫",
-        reason: "花期需要营养时机",
-        effect: "减少虫害风险",
-        date: "2024.08.15",
-    },
-    {
-        name: "梢期营养",
-        reason: "花期需要营养时机",
-        effect: "减少虫害风险",
-        date: "2024.08.01",
-    },
+    { date: "2025.04.10" },
+    { date: "2025.04.03" },
+    { date: "2025.03.26" },
+    { date: "2025.03.15" },
+    { date: "2025.03.08" },
 ]);
 
 const handleItem = (index) => {
     if (index === 0) {
-        sourceList.value = sourceList1.value;
-    }
-    if (index === 1) {
-        sourceList.value = sourceList1.value.slice(0, 3);
-    }
-    if (index === 2) {
-        sourceList.value = sourceList1.value.slice(3);
+        currentRecords.value = [...ALT_RECORDS];
+    } else if (index === 1) {
+        currentRecords.value = ALT_RECORDS.slice(0, 3);
+    } else if (index === 2) {
+        currentRecords.value = ALT_RECORDS.slice(3);
     }
 };
 
@@ -567,30 +483,8 @@ const handleMore = () => {
             line-height: 1.6;
             flex: 1;
             .name {
-                // display: flex;
-                // align-items: center;
                 color: #6c6c6c;
                 font-size: 12px;
-                .main-name {
-                    font-size: 16px;
-                    color: #000;
-                    font-weight: bold;
-                    padding-right: 10px;
-                }
-                div {
-                    margin-left: 5px;
-                    border-radius: 4px;
-                    font-size: 12px;
-                    padding: 2px 5px;
-                    &.mark {
-                        background: rgba(50, 203, 226, 0.25);
-                        color: #00bedb;
-                    }
-                    &.age {
-                        background: rgba(255, 196, 0, 0.2);
-                        color: #f0a400;
-                    }
-                }
                 .val {
                     flex: 1;
                     color: rgba(255, 255, 255, 0.8);

+ 19 - 16
src/views/home/index.vue

@@ -9,18 +9,18 @@
 
             <div class="right yes-events">
                 <div class="list adopt-list-wrap">
-                    <chart-box name="认养管理" arrow="">
+                    <chart-box :name="t('home.adoptManage')" arrow="">
                         <el-tabs v-model="activeName" class="demo-tabs">
-                            <el-tab-pane label="认养列表" name="认养列表">
+                            <el-tab-pane :label="t('home.tabs.adoptList')" name="adoptList">
                                 <adopt-list></adopt-list>
                             </el-tab-pane>
-                            <el-tab-pane label="客户列表" name="客户列表">
+                            <el-tab-pane :label="t('home.tabs.clientList')" name="clientList">
                                 <client-list></client-list>
                             </el-tab-pane>
-                            <el-tab-pane label="认养申请" name="认养申请">
+                            <el-tab-pane :label="t('home.tabs.applyList')" name="applyList">
                                 <apply-list></apply-list>
                             </el-tab-pane>
-                            <el-tab-pane label="确认地址" name="确认地址">
+                            <el-tab-pane :label="t('home.tabs.addressList')" name="addressList">
                                 <address-list></address-list>
                             </el-tab-pane>
                         </el-tabs>
@@ -38,36 +38,36 @@
             <div v-else class="map-bg map-legend yes-events">
                 <div class="item" v-if="ROLE == 1">
                     <img src="@/assets/images/map/status/wry.png" alt="" />
-                    未开放认养
+                    {{ t('home.legend.notOpen') }}
                 </div>
                 <div class="item" v-if="ROLE == 2">
                     <img src="@/assets/images/map/status/other.png" alt="" />
-                    其他树
+                    {{ t('home.legend.otherTree') }}
                 </div>
                 <div class="item" v-show="!checkShow">
                     <img src="@/assets/images/map/status/dry.png" alt="" />
-                    {{ ROLE == 1 ? "待认养" : "可团购" }}
+                    {{ ROLE == 1 ? t('home.legend.pending') : t('home.legend.groupBuy') }}
                 </div>
                 <div class="item" v-show="!checkShow">
                     <img src="@/assets/images/map/status/yry.png" alt="" />
-                    已认养
+                    {{ t('home.legend.adopted') }}
                 </div>
                 <div class="item selected-item" v-show="checkShow">
                     <img src="@/assets/images/map/status/selected.png" alt="" />
-                    已选择
+                    {{ t('home.legend.selected') }}
                 </div>
             </div>
 
             <div class="tips" v-show="checkShow">
                 <div class="text">
-                    <span>提示:</span>请在底图上点选 <span>认养的果树</span>,或按住 Ctrl 框选 <span>认养的区域</span>
+                    <span>{{ t('home.tips.label') }}</span>{{ t('home.tips.prefix') }}<span>{{ t('home.tips.tree') }}</span>{{ t('home.tips.middle') }}<span>{{ t('home.tips.area') }}</span>
                 </div>
             </div>
 
-            <div v-show="!checkShow && ROLE == 1" class="right-button yes-events" @click="hanldeCheck">勾选认养区域</div>
+            <div v-show="!checkShow && ROLE == 1" class="right-button yes-events" @click="hanldeCheck">{{ t('home.selectAdoptArea') }}</div>
             <div v-show="checkShow" class="center-button">
-                <div class="cancel yes-events" @click="handleCancel">取消</div>
-                <div class="yes-events" @click="handleCancel">确认开放认养权限</div>
+                <div class="cancel yes-events" @click="handleCancel">{{ t('home.cancel') }}</div>
+                <div class="yes-events" @click="handleCancel">{{ t('home.confirmOpenAdopt') }}</div>
             </div>
         </div>
     </div>
@@ -76,7 +76,7 @@
     <!-- 图片弹窗 -->
     <PicturePreview :imageUrl="urls" :curIndex="urlsIndex"></PicturePreview>
     <album-carousel></album-carousel>
-    <PdfDialog title="果园报告"></PdfDialog>
+    <PdfDialog :title="t('home.orchardReport')"></PdfDialog>
 </template>
 
 <script setup>
@@ -100,6 +100,9 @@ import { useStore } from "vuex";
 import eventBus from "@/api/eventBus";
 import AlbumCarousel from "./album_compoents/albumCarousel.vue";
 import PdfDialog from "../../components/PdfDialog";
+import { useI18n } from "@/i18n";
+
+const { t } = useI18n();
 let store = useStore();
 const components = {
     homePage,
@@ -109,7 +112,7 @@ const components = {
 const router = useRouter();
 const mapRef = ref(null);
 
-const activeName = ref('认养列表')
+const activeName = ref('adoptList')
 // 用户角色
 store.commit("home/SET_USER_ROLE", 1);