huangxw пре 2 недеља
родитељ
комит
add0fa8db1

+ 6 - 0
src/assets/styles/uview-plus.scss

@@ -43,4 +43,10 @@ uni-button::after{
 }
 .u-alert--primary--light {
     background-color: #EBF6EE;
+}
+
+.paging-btm-shadow {
+    .zp-page-bottom-container {
+        box-shadow: 0px 0px 6rpx 0px #AECEBF;
+    }
 }

+ 55 - 0
src/components/ut-navbar/ut-navbar.vue

@@ -0,0 +1,55 @@
+<template>
+    <up-navbar :fixed="fixed" :border="border">
+        <template #left>
+            <slot name="left">
+                <up-icon v-if="showBack" name="arrow-left" size="40rpx" color="#333" @click="handleBackClick" ></up-icon>
+                <up-icon v-else name="home" size="40rpx" color="#333" @click="handleHomeClick" ></up-icon>
+            </slot>
+        </template>
+        <template #center>
+            <slot name="center">
+                <text class="f-s-38 c-#333 f-w-500">{{ title }}</text>
+            </slot>
+        </template>
+    </up-navbar>
+</template>
+<script lang="ts" setup>
+import { ref, onMounted } from 'vue';
+const props = withDefaults(defineProps<{
+    title?: string;
+    border?: boolean;
+    fixed?: boolean;
+    homeUrl?: string;
+}>(), {
+    title: '',
+    border: true,
+    fixed: true,
+    homeUrl: '/pages/index/index'
+});
+
+const emit = defineEmits<{
+    (e: 'back'): void;
+    (e: 'home'): void;
+}>();
+
+const showBack = ref(false);
+onMounted(() => {
+    const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
+    showBack.value = pages.length > 1;
+});
+
+function handleBackClick() {
+    emit('back');
+    const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
+    if (pages.length > 1) {
+        uni.navigateBack();
+    } else {
+        uni.switchTab({ url: props.homeUrl });
+    }
+}
+
+function handleHomeClick() {
+    emit('home');
+    uni.switchTab({ url: props.homeUrl });
+}
+</script>

+ 162 - 0
src/components/ut-upload/ut-upload.vue

@@ -0,0 +1,162 @@
+<template>
+	<u-upload :width="width" :height="height" :fileList="fileList" :accept="accept" :uploadIcon="uploadIcon"
+		:uploadText="uploadText" @afterRead="afterRead" @delete="deletePic" :multiple="multiple"
+		:maxCount="maxCount">
+	</u-upload>
+</template>
+
+<script setup lang="ts">
+import upload from '@/utils/upload';
+
+interface FileItem {
+    url: string;
+}
+
+interface UploadEvent {
+    file: Array<{ url: string }>;
+}
+
+interface DeleteEvent {
+    index: number;
+}
+
+interface Props {
+    modelValue: string | string[] | Record<string, any> | null;
+    maxCount: number;
+    width: string;
+    height: string;
+    multiple: boolean;
+    uploadText: string;
+    uploadIcon: string;
+    accept: string;
+    isArr: boolean;
+    keyUrl: string;
+    isObject: boolean;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+    modelValue: () => [],
+    maxCount: 1,
+    width: '200rpx',
+    height: '200rpx',
+    multiple: true,
+    uploadText: '点击上传',
+    uploadIcon: 'plus',
+    accept: 'image',
+    isArr: false,
+    keyUrl: '',
+    isObject: false
+});
+
+const emit = defineEmits<{
+    change: [value: any];
+    'update:modelValue': [value: any];
+}>();
+
+const fileList = ref<FileItem[]>([]);
+
+watch(() => props.modelValue, (ov) => {
+    if (ov) {
+        if (props.isObject) {
+            fileList.value = [ov as FileItem];
+        } else if (props.isArr) {
+            if (props.keyUrl) {
+                fileList.value = (ov as any[]).map(url => ({ url: url[props.keyUrl] }));
+            } else {
+                fileList.value = (ov as string[]).map(url => ({ url }));
+            }
+        } else {
+            const list = (ov as string).split(',');
+            fileList.value = list.map(item => ({
+                url: item
+            }));
+        }
+    }
+});
+
+const deletePic = (event: DeleteEvent) => {
+    fileList.value.splice(event.index, 1);
+    const urls = fileList.value.map(({ url }) => url);
+    const imgs = urls.toString();
+    
+    if (props.isObject) {
+        emit('update:modelValue', null);
+        emit('change', null);
+    } else if (props.isArr) {
+        if (props.keyUrl) {
+            emit('update:modelValue', fileList.value.map(({ url }) => ({ [props.keyUrl]: url })));
+            emit('change', fileList.value.map(({ url }) => ({ [props.keyUrl]: url })));
+        } else {
+            emit('update:modelValue', urls);
+            emit('change', urls);
+        }
+    } else {
+        emit('update:modelValue', imgs);
+        emit('change', imgs);
+    }
+};
+
+const afterRead = async (event: UploadEvent) => {
+    const files = event.file;
+    console.log(files);
+    
+    // 先使用本地临时路径进行预览展示
+    const startIndex = fileList.value.length;
+    const tempItems = files.map(({ url }) => ({ url }));
+    fileList.value = fileList.value.concat(tempItems);
+
+    // 同步上传并在成功后用服务端URL替换临时预览
+    const promises = files.map(({ url }) => upload({
+        filePath: url,
+        url: '/resource/oss/upload'
+    }));
+
+    try {
+        const res = await Promise.all(promises);
+        const uploaded: FileItem[] = [];
+        res.forEach(({ code, data }) => {
+            if (code === 200) {
+                uploaded.push(data);
+            } else {
+                uploaded.push({ url: '' });
+            }
+        });
+
+        // 替换对应位置的临时项为服务器返回的URL(成功的替换,失败的不动或清理)
+        uploaded.forEach((item, i) => {
+            const targetIndex = startIndex + i;
+            if (item.url) {
+                fileList.value[targetIndex] = item;
+            } else {
+                // 上传失败则移除该临时项
+                fileList.value.splice(targetIndex, 1);
+            }
+        });
+
+        const urls = fileList.value.slice(0); // 当前所有成功项
+        const imgs = urls.map(({ url }) => url).toString();
+
+        if (props.isObject) {
+            emit('update:modelValue', urls[0]);
+            emit('change', urls[0]);
+        } else if (props.isArr) {
+            if (props.keyUrl) {
+                emit('update:modelValue', urls.map(({ url }) => ({ [props.keyUrl]: url })));
+                emit('change', urls.map(({ url }) => ({ [props.keyUrl]: url })));
+            } else {
+                emit('update:modelValue', urls.map(({ url }) => url));
+                emit('change', urls.map(({ url }) => url));
+            }
+        } else {
+            emit('update:modelValue', imgs);
+            emit('change', imgs);
+        }
+    } catch (error) {
+        console.error('Upload failed:', error);
+        // 全部上传失败则回滚新增的临时项
+        fileList.value.splice(startIndex, tempItems.length);
+    }
+};
+</script>
+
+<style></style>

+ 7 - 0
src/pages.json

@@ -120,6 +120,13 @@
                     "style": {
                         "navigationBarTitleText": "选择企业成员"
                     }
+                },
+                // 选择种养殖品种
+                {
+                    "path": "select-medicine/index",
+                    "style": {
+                        "navigationBarTitleText": "选择种养殖品种"
+                    }
                 }
             ]
         }

+ 0 - 332
src/plant/base/base-edit/models/base-info/base-info.vue

@@ -1,332 +0,0 @@
-<template>
-    <view class="z-paging-wrap">
-        <z-paging class="" ref="paging" bgColor="#fff" :fixed="false" safe-area-inset-bottom scroll-with-animation>
-            <view class="pd-24">
-                <up-alert type="primary" fontSize="24rpx" description="注意:基地不强制与品种挂钩!基地地址以行政村为界,可成片集中或相对集中,跨村则视为另一基地(连片跨村除外)。"></up-alert>
-                <view class="pd-10"></view>
-                <up-form class="p-rtv" labelPosition="top" :model="form" :rules="rules" labelWidth="auto" ref="upFormRef">
-                    <!-- 校验定位:基地类型 -->
-                    <view class="h-1" id="baseTypepppp"></view>
-                    <ut-action-sheet v-model="form.baseType" :tabs="pt_base_type" title="选择基地类型">
-                        <up-form-item borderBottom label="基地类型" required prop="baseType">
-                            <view v-if="form.baseType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_base_type, form.baseType) }}</view>
-                            <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择基地类型</view>
-                            <template #right>
-                                <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
-                            </template>
-                        </up-form-item>
-                    </ut-action-sheet>
-                    <!-- 基地名称 -->
-                    <view class="h-1" id="baseNamepppp"></view>
-                    <up-form-item borderBottom label="基地名称" required prop="baseName">
-                        <up-input v-model="form.baseName" placeholder="请输入基地名称" border="none" clearable></up-input>
-                    </up-form-item>
-                    <!-- 基地编号 -->
-                    <view class="h-1" id="baseCodepppp"></view>
-                    <up-form-item borderBottom label="基地编号" prop="baseCode">
-                        <up-input v-model="form.baseCode" placeholder="请输入基地编号" border="none" clearable></up-input>
-                    </up-form-item>
-                    <!-- 校验定位:建设时间 -->
-                    <view class="h-1" id="buildDatepppp"></view>
-                    <ut-datetime-picker v-model="form.buildDate" mode="date" dateFields="month">
-                        <up-form-item borderBottom label="建设时间" required prop="buildDate">
-                            <up-input v-model="form.buildDate" placeholder="请选择基地建设年份" border="none" clearable></up-input>
-                        </up-form-item>
-                    </ut-datetime-picker>
-                    <!-- 选择基地组织方式 -->
-                    <view class="h-1" id="orgTypepppp"></view>
-                    <ut-action-sheet v-model="form.orgType" :tabs="pt_org_type" title="选择基地组织方式">
-                        <up-form-item borderBottom label="基地组织方式" required prop="orgType">
-                            <view v-if="form.orgType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_org_type, form.orgType) }}</view>
-                            <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择基地组织方式</view>
-                            <template #right>
-                                <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
-                            </template>
-                        </up-form-item>
-                    </ut-action-sheet>
-                    <!-- 选择基地负责人 -->
-                    <!-- 校验定位:基地负责人 -->
-                    <view class="h-1" id="contactIdpppp"></view>
-                    <up-form-item @click="selectCpyMember" borderBottom label="基地负责人" required prop="contactId">
-                        <view v-if="form.contactId" class="f-s-30 c-333 f-w-5 flex1">{{ form.contactName }}</view>
-                        <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择基地负责人</view>
-                        <template #right>
-                            <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
-                        </template>
-                    </up-form-item>
-                    <!-- 填写基地联系电话 -->
-                    <view class="h-1" id="contactTelpppp"></view>
-                    <up-form-item borderBottom label="基地联系电话" required prop="contactTel">
-                        <up-input v-model="form.contactTel" placeholder="请输入基地联系电话" border="none" clearable></up-input>
-                    </up-form-item>
-                    <!-- 是否Gap基地 -->
-                    <view class="h-1" id="gapFlagpppp"></view>
-                    <up-form-item borderBottom label="是否为Gap基地" required prop="gapFlag">
-                        <up-radio-group v-model="form.gapFlag">
-                            <up-radio :customStyle="{ marginRight: '60rpx' }" v-for="(item, index) in yes_no" :key="index" :label="item.label" :name="item.value"></up-radio>
-                        </up-radio-group>
-                    </up-form-item>
-                    <view class="h-1" id="adcodepppp"></view>
-                    <up-form-item @click="showArea = true" borderBottom label="基地具体地址" required prop="gapInfo.adcode">
-                        <!-- <up-input v-model="form.address" placeholder="请选择基地所在省/市/县/镇(乡)" border="none" clearable></up-input> -->
-                        <view v-if="form?.gapInfo?.adcode" class="f-s-30 c-333 f-w-5 flex1">{{ form?.gapInfo?.adcodeName }}</view>
-                        <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择基地所在省/市/县/镇(乡)</view>
-                        <template #right>
-                            <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
-                        </template>
-                    </up-form-item>
-                    <up-form-item borderBottom prop="gapInfo.address">
-                        <up-input v-model="form.gapInfo.address" placeholder="请填写村级以下的具体地址信息" border="none" clearable></up-input>
-                    </up-form-item>
-                    <up-form-item borderBottom>
-                        <view class="flex1 ov-hd">
-                            <view class="d-flex a-c mb-10" style="margin-bottom: 5px">
-                                <view class="f-s-30 c-#666">基地范围</view>
-                            </view>
-                            <view class="bg-#ccc d-flex ov-hd p-rtv" @click="mapDrawArea">
-                                <image class="w-full h-380" v-if="form.gapInfo?.basePic" :src="form.gapInfo.basePic" mode="widthFix" />
-                                <image class="w-full h-380" v-else src="@/static/images/plant/base/select_base_gap.png" mode="widthFix" />
-                                <view v-if="!form.gapInfo?.basePic" class="btn-aree-center d-flex flex-cln a-c j-c">
-                                    <image class="w-52 h-52 mb-10" src="@/static/images/plant/base/draw_area_icon.png" mode="widthFix" />
-                                    <view class="c-primary f-s-28 f-w-400">点击绘制基地范围</view>
-                                </view>
-                            </view>
-                        </view>
-                    </up-form-item>
-                    <view class="h-1" id="areaPppp"></view>
-                    <up-form-item required borderBottom label="基地面积" prop="gapInfo.area">
-                        <up-input v-model="form.gapInfo.area" placeholder="地块绘制后自动带出可修改" border="none" clearable></up-input>
-                        <template #right>
-                            <span>{{ form.gapInfo.areaUnit }}</span>
-                        </template>
-                    </up-form-item>
-                    <!-- 基地经纬度 -->
-                    <view class="h-1" id="lnglatpppp"></view>
-                    <up-form-item required label="基地经纬度" prop="longitudeLatitude">
-                        <view class="flex1 d-flex a-c">
-                            <up-input v-model="form.gapInfo.lng" border="bottom" placeholder="70-150内的经度数值" clearable></up-input>
-                            <view class="pd-5"></view>
-                            <up-input v-model="form.gapInfo.lat" placeholder="4-53内的纬度数值" border="bottom" clearable></up-input>
-                        </view>
-                    </up-form-item>
-                </up-form>
-            </view>
-            <template #bottom>
-                <view class="pd-20 d-flex">
-                    <up-button @click="saveBaseInfo" class="mr-30" color="#F19F18" type="primary">暂存</up-button>
-                    <up-button @click="submitForm" type="primary">提交</up-button>
-                </view>
-            </template>
-        </z-paging>
-    </view>
-    <ut-picker-area v-model:show="showArea" v-model="form.gapInfo.adcode" @confirm="confirmArea"></ut-picker-area>
-</template>
-<script setup lang="ts" name="base-info">
-import { isOpenSetting } from '@/utils/common';
-import { generateUniqueId } from '@/utils/public';
-import { useClientRequest } from '@/utils/request';
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { yes_no, pt_org_type, pt_base_type } = toRefs<any>(proxy?.useDict('yes_no', 'pt_org_type', 'pt_base_type'));
-const paging = ref<any>(null);
-const upFormRef = ref<any>(null);
-const showArea = ref(false);
-const form = ref<any>({
-    baseType: '',
-    baseName: '',
-    baseCode: '',
-    gapInfo: {
-        adcode: '',
-        adcodeName: '',
-        address: '',
-        areaUnit: '亩',
-        area: undefined
-    },
-    randomCode: generateUniqueId(),
-    // 当前位置经纬度
-    longitudeLatitude: {
-        lng: '',
-        lat: '',
-    },
-    coordinates: [],
-});
-const rules = reactive({
-    baseType: [{ required: true, message: '请选择基地类型', trigger: ['change'] }],
-    baseName: [{ required: true, message: '请输入基地名称', trigger: ['blur', 'change'] }],
-    buildDate: [{ required: true, message: '请选择基地建设年份', trigger: ['change'] }],
-    orgType: [{ required: true, message: '请选择基地组织方式', trigger: ['change'] }],
-    contactId: [{ required: true, message: '请选择基地负责人', trigger: ['change'] }],
-    contactTel: [{ required: true, message: '请输入基地联系电话', trigger: ['blur'] }],
-    gapFlag: [{ required: true, message: '请选择是否为Gap基地', trigger: ['change'] }],
-    'gapInfo.adcode': [{ required: true, message: '请选择基地所在省/市/县/镇(乡)', trigger: ['change'] }],
-    'gapInfo.area': [{ required: true, message: '请填写基地面积', trigger: ['change'] }],
-    longitudeLatitude: [
-        {
-            message: '请填写有效的经纬度(经度70-150,纬度4-53)',
-            validator: (rule: any, value: any) => {
-                const lng = Number(form.value?.gapInfo?.lng);
-                const lat = Number(form.value?.gapInfo?.lat);
-                if (!lng || !lat) return false;
-                if (Number.isNaN(lng) || Number.isNaN(lat)) return false;
-                return lng >= 70 && lng <= 150 && lat >= 4 && lat <= 53;
-            },
-            trigger: ['blur', 'change'],
-        },
-    ],
-});
-// saveInfo和submitForm防抖
-// 暂存基地信息
-const saveBaseInfo = async () => {
-    uni.$u.debounce(
-        async () => {
-            // 提交表单
-            uni.showLoading({
-                title: '保存中...',
-            });
-            try {
-                const res = await useClientRequest.post('/plt-api/app/base/temp', form.value);
-                uni.hideLoading();
-                if (!res || res !== 200) return;
-                uni.showToast({
-                    title: '保存成功',
-                    icon: 'success',
-                });
-            } catch (error) {
-                uni.hideLoading();
-            }
-        },
-        500,
-        true
-    );
-};
-const submitForm = async () => {
-    uni.$u.debounce(
-        async () => {
-            try {
-                await upFormRef.value?.validate();
-            } catch (error: any) {
-                console.log(form.value);
-                
-                console.log(error, '++++++++');
-                // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop;
-                paging.value?.scrollIntoViewById(firstErrorField, 30, true);
-                return;
-            }
-            // 提交表单
-            uni.showLoading({
-                title: '提交中...',
-            });
-            try {
-                const res = await useClientRequest.post('/plt-api/app/base/add', form.value);
-                uni.hideLoading();
-                if (!res || res !== 200) return;
-                uni.hideLoading();
-                uni.showToast({
-                    title: '提交成功',
-                    icon: 'success',
-                });
-                // 返回上一页
-                setTimeout(() => {
-                    uni.navigateBack();
-                }, 1500);
-            } catch (error) {
-                uni.hideLoading();
-            }
-        },
-        500,
-        true
-    );
-};
-
-const mapDrawArea = async () => {
-    uni.$on('mapAreaData', (data: any) => {
-        // 这里可以将 data 赋值给 form 中的相应字段
-        form.value.gapInfo.basePic = data.gapInfo.basePic;
-        form.value.gapInfo.area = String(data.gapInfo.area);
-        form.value.gapInfo.areaUnit = data.gapInfo.areaUnit;
-        form.value.coordinates = data.coordinates;
-        uni.$off('mapAreaData');
-    });
-    if (form.value.gapInfo?.basePic) {
-        // 暂存地图当前数据后跳转
-        await useClientRequest.post('/plt-api/app/gapCertificationInfo/painting', {
-            randomCode: form.value.id || form.value.randomCode,
-            value: JSON.stringify({
-                gapInfo: form.value.gapInfo,
-                coordinates: form.value.coordinates,
-            }),
-        });
-    }
-    uni.$u.route({
-        type: 'navigateTo',
-        url: '/tools/map-draw-area/index',
-        params: {
-            drawId: form.value.id || form.value.randomCode,
-            unit: form.value.gapInfo.areaUnit || '亩',
-            lng: form.value.gapInfo.lng || form.value.longitudeLatitude.lng || '',
-            lat: form.value.gapInfo.lat || form.value.longitudeLatitude.lat || '',
-        },
-    });
-};
-
-const selectCpyMember = () => {
-    uni.$on('selectCpyMember', (item: any) => {
-        form.value.contactId = item.userInfo?.id;
-        form.value.contactName = item.userInfo?.name;
-        form.value.contactTel = item.userInfo?.phone;
-        uni.$off('selectCpyMember');
-    });
-    uni.$u.route({
-        type: 'navigateTo',
-        url: '/tools/select-cpy-member/index',
-    });
-};
-const confirmArea = (area: any) => {
-    form.value.gapInfo.adcodeName = area.fullName;
-};
-onLoad((optins: any) => {
-    if (optins.id) {
-    } else {
-        getLocationByAddress();
-    }
-});
-// 获取当前经纬度返回地址
-const getLocationByAddress = async () => {
-    const info = await uni.getSystemInfo();
-    let locationEnabled = info.locationEnabled; //判断手机定位服务是否开启
-    let locationAuthorized = info.locationAuthorized; //判断定位服务是否允许微信授权
-    if (locationEnabled == false || locationAuthorized == false) {
-        //手机定位服务(GPS)未授权
-        uni.showModal({
-            title: '提示',
-            content: '请打开定位服务功能',
-            showCancel: false, // 不显示取消按钮
-        });
-        return;
-    }
-
-    const scope = await isOpenSetting('scope.userLocation');
-    if (!scope) return;
-    const location = await uni.getLocation({ type: 'gcj02', isHighAccuracy: true });
-    form.value.longitudeLatitude = {
-        lng: location.longitude,
-        lat: location.latitude,
-    };
-};
-</script>
-<style lang="scss" scoped>
-.z-paging-wrap {
-    position: absolute;
-    right: 0;
-    top: 0;
-    bottom: 0;
-    left: 0;
-}
-.btn-aree-center {
-    position: absolute;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    left: 0;
-}
-</style>

+ 0 - 3
src/plant/base/base-edit/models/environment-info/environment-info.vue

@@ -1,3 +0,0 @@
-<template>
-    <view>内容</view>
-</template>

+ 0 - 3
src/plant/base/base-edit/models/plot-info/plot-info.vue

@@ -1,3 +0,0 @@
-<template>
-    <view>内容</view>
-</template>

+ 337 - 2
src/plant/base/gap-base-info-edit/index.vue

@@ -1,3 +1,338 @@
 <template>
-    <view>页面内容</view>
-</template>
+    <z-paging class="" ref="paging" bgColor="#fff" paging-class="paging-btm-shadow" safe-area-inset-bottom scroll-with-animation>
+        <template #top>
+            <ut-navbar title="添加GAP基地信息" :fixed="false" border></ut-navbar>
+        </template>
+        <view class="pd-24">
+            <up-form class="p-rtv" labelPosition="top" :model="form" :rules="rules" labelWidth="auto" ref="upFormRef">
+                <!-- 校验定位:基地类型 -->
+                <!-- 基地信息部分 -->
+                <view>
+                    <view class="h-1" id="gapBaseTypepppp"></view>
+                    <ut-action-sheet v-model="form.gapBaseType" :tabs="pt_base_type" title="选择基地类型">
+                        <up-form-item borderBottom label="基地类型" required prop="baseType">
+                            <view v-if="form.gapBaseType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_base_type, form.gapBaseType) }}</view>
+                            <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择基地类型</view>
+                            <template #right>
+                                <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                            </template>
+                        </up-form-item>
+                    </ut-action-sheet>
+                    <!-- 基地名称 -->
+                    <view class="h-1" id="baseNamepppp"></view>
+                    <up-form-item borderBottom label="基地名称" required prop="gapBaseName">
+                        <up-input v-model="form.gapBaseName" placeholder="请输入基地名称" border="none" clearable></up-input>
+                    </up-form-item>
+                    <!-- 选择种养殖品种 -->
+                    <view class="h-1" id="medicineIdpppp"></view>
+                    <up-form-item @click="selectMedicine" borderBottom label="种养殖品种" required prop="medicineId">
+                        <view v-if="form.medicineId" class="f-s-30 c-333 f-w-5 flex1">{{ form.contactName }}</view>
+                        <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择种养殖品种</view>
+                        <template #right>
+                            <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                        </template>
+                    </up-form-item>
+
+                    <up-form-item borderBottom prop="basePic" required>
+                        <view class="flex1 ov-hd">
+                            <view class="d-flex a-c mb-10" style="margin-bottom: 5px">
+                                <view class="f-s-30 c-#666">基地范围</view>
+                            </view>
+                            <view class="bg-#ccc d-flex ov-hd p-rtv" @click="mapDrawArea">
+                                <image class="w-full h-380" v-if="form?.basePic" :src="form?.basePic" mode="widthFix" />
+                                <image class="w-full h-380" v-else src="@/static/images/plant/base/select_base_gap.png" mode="widthFix" />
+                                <view v-if="!form?.basePic" class="btn-aree-center d-flex flex-cln a-c j-c">
+                                    <image class="w-52 h-52 mb-10" src="@/static/images/plant/base/draw_area_icon.png" mode="widthFix" />
+                                    <view class="c-primary f-s-28 f-w-400">点击绘制基地范围</view>
+                                </view>
+                            </view>
+                        </view>
+                    </up-form-item>
+                    <view class="h-1" id="adcodepppp"></view>
+                    <up-form-item @click="showArea = true" borderBottom label="基地具体地址" required prop="adcode">
+                        <!-- <up-input v-model="form.address" placeholder="请选择基地所在省/市/县/镇(乡)" border="none" clearable></up-input> -->
+                        <view v-if="form?.adcode" class="f-s-30 c-333 f-w-5 flex1">{{ form?.adcodeName }}</view>
+                        <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择基地所在省/市/县/镇(乡)</view>
+                        <template #right>
+                            <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                        </template>
+                    </up-form-item>
+                    <up-form-item borderBottom prop="address">
+                        <up-input v-model="form.address" placeholder="请填写村级以下的具体地址信息" border="none" clearable></up-input>
+                    </up-form-item>
+
+                    <view class="h-1" id="areaPppp"></view>
+                    <up-form-item required borderBottom label="基地面积" prop="area">
+                        <up-input v-model="form.area" placeholder="地块绘制后自动带出可修改" border="none" clearable></up-input>
+                        <template #right>
+                            <span>{{ form.gapInfo.areaUnit }}</span>
+                        </template>
+                    </up-form-item>
+                    <!-- 基地经纬度 -->
+                    <view class="h-1" id="longitudeLatitudepppp"></view>
+                    <up-form-item required label="基地经纬度" prop="longitudeLatitude">
+                        <view class="flex1 d-flex a-c">
+                            <up-input v-model="form.lng" border="bottom" placeholder="70-150内的经度数值" clearable></up-input>
+                            <view class="pd-5"></view>
+                            <up-input v-model="form.lat" placeholder="4-53内的纬度数值" border="bottom" clearable></up-input>
+                        </view>
+                    </up-form-item>
+                    <!-- 校验定位:建设时间 -->
+                    <view class="h-1" id="ratedDatepppp"></view>
+                    <ut-datetime-picker v-model="form.ratedDate" mode="date" dateFields="month">
+                        <up-form-item borderBottom label="获评GAP基地时间" required prop="ratedDate">
+                            <up-input v-model="form.ratedDate" placeholder="请选择获评GAP基地时间" border="none" clearable></up-input>
+                            <template #right>
+                                <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                            </template>
+                        </up-form-item>
+                    </ut-datetime-picker>
+                    <!-- 官方公示证明材料 -->
+                    <view class="h-1" id="certFilepppp"></view>
+                    <up-form-item borderBottom required prop="certFile">
+                        <view class="flex1">
+                            <view style="margin-bottom: 10rpx">
+                                <span class="c-666 f-s-30">官方公示证明材料</span>
+                                <span class="f-s-26 c-999">(可上传9张)</span>
+                            </view>
+                            <ut-upload v-model="form.certFile" :max-count="9"></ut-upload>
+                        </view>
+                    </up-form-item>
+                    <!-- 官方公示网址 -->
+                    <view class="h-1" id="certUrlpppp"></view>
+                    <up-form-item borderBottom label="官方公示网址" prop="certUrl">
+                        <up-input v-model="form.certUrl" placeholder="请输入官方公示网址" border="none" clearable></up-input>
+                    </up-form-item>
+                </view>
+            </up-form>
+        </view>
+        <template #bottom>
+            <view class="pd-20 d-flex base-bottom-wrap">
+                <up-button @click="submitForm" type="primary">提交</up-button>
+            </view>
+        </template>
+    </z-paging>
+    <ut-picker-area v-show:show="showArea" v-model="form.adcode" @confirm="confirmArea"></ut-picker-area>
+</template>
+<script setup lang="ts">
+import { useUserStore } from '@/store';
+import { useClientRequest } from '@/utils/request';
+import { isOpenSetting } from '@/utils/common';
+import { generateUniqueId } from '@/utils/public';
+const tabs = reactive([
+    { label: '基本信息', value: 'base' },
+    { label: '地块信息', value: 'plot' },
+    { label: '选址依据及环境信息', value: 'environment' },
+]);
+const activeTab = ref('base');
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { yes_no, pt_org_type, pt_base_type } = toRefs<any>(proxy?.useDict('yes_no', 'pt_org_type', 'pt_base_type'));
+const paging = ref<any>(null);
+const upFormRef = ref<any>(null);
+const showArea = ref(false);
+const form = ref<any>({
+    sourceType: '2', // 基地来源 1-GAP系统 2-手动录入
+    gapBaseType: '',
+    baseName: '',
+    baseCode: '',
+    gapInfo: {
+        adcode: '',
+        adcodeName: '',
+        address: '',
+        areaUnit: '亩',
+        area: undefined,
+    },
+    randomCode: generateUniqueId(),
+    // 当前位置经纬度
+    longitudeLatitude: {
+        lng: '',
+        lat: '',
+    },
+    coordinates: [],
+});
+const rules = reactive({
+    baseType: [{ required: true, message: '请选择基地类型', trigger: ['change'] }],
+    baseName: [{ required: true, message: '请输入基地名称', trigger: ['blur', 'change'] }],
+    buildDate: [{ required: true, message: '请选择基地建设年份', trigger: ['change'] }],
+    orgType: [{ required: true, message: '请选择基地组织方式', trigger: ['change'] }],
+    contactId: [{ required: true, message: '请选择基地负责人', trigger: ['change'] }],
+    contactTel: [{ required: true, message: '请输入基地联系电话', trigger: ['blur'] }],
+    gapFlag: [{ required: true, message: '请选择是否为Gap基地', trigger: ['change'] }],
+    adcode: [{ required: true, message: '请选择基地所在省/市/县/镇(乡)', trigger: ['change'] }],
+    area: [{ required: true, message: '请填写基地面积', trigger: ['change'] }],
+    longitudeLatitude: [
+        {
+            message: '请填写有效的经纬度(经度70-150,纬度4-53)',
+            validator: (rule: any, value: any) => {
+                const lng = Number(form.value?.lng);
+                const lat = Number(form.value?.lat);
+                if (!lng || !lat) return false;
+                if (Number.isNaN(lng) || Number.isNaN(lat)) return false;
+                return lng >= 70 && lng <= 150 && lat >= 4 && lat <= 53;
+            },
+            trigger: ['blur', 'change'],
+        },
+    ],
+});
+// saveInfo和submitForm防抖
+// 暂存基地信息
+const saveBaseInfo = async () => {
+    uni.$u.debounce(
+        async () => {
+            // 提交表单
+            uni.showLoading({
+                title: '保存中...',
+            });
+            try {
+                const res = await useClientRequest.post('/plt-api/app/base/temp', form.value);
+                uni.hideLoading();
+                if (!res || res !== 200) return;
+                uni.showToast({
+                    title: '保存成功',
+                    icon: 'success',
+                });
+            } catch (error) {
+                uni.hideLoading();
+            }
+        },
+        500,
+        true
+    );
+};
+const submitForm = async () => {
+    uni.$u.debounce(
+        async () => {
+            try {
+                await upFormRef.value?.validate();
+            } catch (error: any) {
+                // 滚动到第一个错误字段
+                const firstErrorField = error && error[0].prop;
+                paging.value?.scrollIntoViewById(firstErrorField, 30, true);
+                return;
+            }
+            // 提交表单
+            uni.showLoading({
+                title: '提交中...',
+            });
+            try {
+                const res = await useClientRequest.post('/plt-api/app/gapCertificationInfo/add', form.value);
+                uni.hideLoading();
+                if (!res || res !== 200) return;
+                uni.hideLoading();
+                uni.showToast({
+                    title: '提交成功',
+                    icon: 'success',
+                });
+                // 返回上一页
+                setTimeout(() => {
+                    uni.navigateBack();
+                }, 1500);
+            } catch (error) {
+                uni.hideLoading();
+            }
+        },
+        500,
+        true
+    );
+};
+
+const mapDrawArea = async () => {
+    uni.$on('mapAreaData', (data: any) => {
+        // 这里可以将 data 赋值给 form 中的相应字段
+        form.value.basePic = data.gapInfo.basePic;
+        form.value.area = String(data.gapInfo.area);
+        form.value.areaUnit = data.gapInfo.areaUnit;
+        form.value.coordinates = data.coordinates;
+        form.value.lng = data.mapInfo.lng;
+        form.value.lat = data.mapInfo.lat;
+        form.value.zoom = data.mapInfo.zoom;
+        uni.$off('mapAreaData');
+    });
+    if (form.value?.basePic) {
+        // 暂存地图当前数据后跳转
+        await useClientRequest.post('/plt-api/app/gapCertificationInfo/painting', {
+            randomCode: form.value.id || form.value.randomCode,
+            value: JSON.stringify({
+                gapInfo: form.value,
+                coordinates: form.value.coordinates,
+            }),
+        });
+    }
+    uni.$u.route({
+        type: 'navigateTo',
+        url: '/tools/map-draw-area/index',
+        params: {
+            drawId: form.value.id || form.value.randomCode,
+            unit: form.value.areaUnit || '亩',
+            lng: form.value.lng || form.value.longitudeLatitude.lng || '',
+            lat: form.value.lat || form.value.longitudeLatitude.lat || '',
+            zoom: form.value.zoom,
+        },
+    });
+};
+
+// 改成去选择种养殖品种页面
+const selectMedicine = () => {
+    uni.$on('medicineSelected', (medicine: any) => {
+        form.value.medicineId = medicine.id;
+        form.value.contactName = medicine.medicineName;
+        uni.$off('medicineSelected');
+    });
+    uni.$u.route({
+        type: 'navigateTo',
+        url: '/tools/select-medicine/index',
+        params: {
+            singleSelect: true,
+        },
+    });
+};
+const confirmArea = (area: any) => {
+    form.value.gapInfo.adcodeName = area.fullName;
+};
+onLoad((optins: any) => {
+    if (optins.id) {
+    } else {
+        getLocationByAddress();
+    }
+});
+// 获取当前经纬度返回地址
+const getLocationByAddress = async () => {
+    const info = await uni.getSystemInfo();
+    let locationEnabled = info.locationEnabled; //判断手机定位服务是否开启
+    let locationAuthorized = info.locationAuthorized; //判断定位服务是否允许微信授权
+    if (locationEnabled == false || locationAuthorized == false) {
+        //手机定位服务(GPS)未授权
+        uni.showModal({
+            title: '提示',
+            content: '请打开定位服务功能',
+            showCancel: false, // 不显示取消按钮
+        });
+        return;
+    }
+
+    const scope = await isOpenSetting('scope.userLocation');
+    if (!scope) return;
+    const location = await uni.getLocation({ type: 'gcj02', isHighAccuracy: true });
+    form.value.longitudeLatitude = {
+        lng: location.longitude,
+        lat: location.latitude,
+    };
+};
+</script>
+<style lang="scss" scoped>
+.z-paging-wrap {
+    position: absolute;
+    right: 0;
+    top: 0;
+    bottom: 0;
+    left: 0;
+}
+
+.btn-aree-center {
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+}
+</style>

+ 10 - 8
src/plant/base/gap-base-info/index.vue

@@ -1,7 +1,7 @@
 <template>
-    <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" @query="query" safe-area-inset-bottom hide-empty-view>
+    <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" @query="query" safe-area-inset-bottom>
         <template #top>
-            <up-navbar title="GAP基地信息" @leftClick="navigateBackOrHome()" :fixed="false"></up-navbar>
+            <ut-navbar title="GAP基地信息" :fixed="false" border></ut-navbar>
             <view class="d-flex a-c pd-25">
                 <view class="min-w-170 flex1">
                     <ut-action-sheet v-model="form.type" :tabs="tabs" @change="onRefresh" title="选择基地类型">
@@ -51,26 +51,28 @@
                 </view>
             </template>
             <!-- 空数据处理 -->
-            <template #empty v-if="!address && list.length === 0">
-                <ut-empty class="mg-at" size="28rpx" color="#999" padding="10rpx" image="/static/images/plant/noEmptyBase.png">非云南省内企业,无法获取已获评的GAP基地信息~</ut-empty>
-                <view class="d-flex j-c f-s-28 c-#ccc">可点击底部按钮上传佐证材料添加获评信息</view>
-            </template>
-            <template #empty v-if="address && list.length === 0">
+          
+            <template #empty v-if="address">
                 <ut-empty class="mg-at" size="28rpx" color="#999" padding="10rpx" image="/static/images/plant/noEmptyBase.png">暂无获评GAP基地信息~</ut-empty>
                 <view class="d-flex j-c f-s-28 c-#ccc">如需认定GAP基地,可前往数字云药官网进行申报</view>
                 <view class="d-flex j-c f-s-28 c-primary pd-15">https://www.shuziyunyao.com/</view>
                 <up-button type="primary" class="b-radius" style="width: 340rpx" @click="copyText('https://www.shuziyunyao.com/')">复制网址</up-button>
             </template>
         </template>
+          <template #empty v-if="!address">
+                <ut-empty class="mg-at" size="28rpx" color="#999" padding="10rpx" image="/static/images/plant/noEmptyBase.png">非云南省内企业,无法获取已获评的GAP基地信息~</ut-empty>
+                <view class="d-flex j-c f-s-28 c-#ccc">可点击底部按钮上传佐证材料添加获评信息</view>
+            </template>
         <template #bottom v-if="!address">
             <view class="base-bottom-wrap pd-20 pb-0">
-                <up-button type="primary">
+                <up-button type="primary" @click="$u.route({ url: '/plant/base/gap-base-info-edit/index' })">
                     <img class="w-38 h-36 mr-10" src="/static/images/plant/chooseGAP.png" alt="" mode="widthFix" />
                     <text>添加GAP基地信息</text>
                 </up-button>
             </view>
         </template>
     </z-paging>
+
 </template>
 <script setup lang="ts">
 import { copyText } from '@/utils/public';

+ 1 - 2
src/tools/select-cpy-member/index.vue

@@ -1,7 +1,7 @@
 <template>
     <z-paging ref="paging" safe-area-inset-bottom v-model="list" @query="query">
         <template #top>
-            <up-navbar title="选择企业负责人" border :fixed="false"></up-navbar>
+            <ut-navbar title="选择企业负责人" :fixed="false" border></ut-navbar>
             <view class="pd-20">
                 <ut-search margin="0" height="68rpx" fontSize="26rpx" placeholder="请输入企业负责人姓名" border v-model="form.keyword" @search="onRefresh"></ut-search>
             </view>
@@ -31,7 +31,6 @@ const query = async (pageNum: number, pageSize: number) => {
         ...form.value,
         pageNum: pageNum,
         pageSize: pageSize,
-        cpyid: '1795009980763025410',
     });
     if (res.code == 200) {
         paging.value.complete(res.rows || []);

+ 57 - 0
src/tools/select-medicine/index.vue

@@ -0,0 +1,57 @@
+<template>
+    <z-paging ref="paging" safe-area-inset-bottom v-model="list" @query="query">
+        <template #top>
+            <ut-navbar title="选择种养殖品种" :fixed="false" border></ut-navbar>
+            <view class="pd-20">
+                <ut-search margin="0" height="68rpx" fontSize="26rpx" placeholder="请输入种养殖品种名称" border v-model="form.keyword" @search="onRefresh"></ut-search>
+            </view>
+        </template>
+        <view class="base-content pd-20">
+            <view :class="{ active: item.id === checkedId }" v-for="(item, index) in list" :key="item.id" @click="clickItem(item)" class="bg-fff mb-10 pd-20 select-item-card">
+                <view class="f-s-30 c-#333 f-w-600">{{ item?.varietyName }}</view>
+                    <view class="f-s-28 c-#999">{{ item.latinName }}</view>
+            </view>
+        </view>
+    </z-paging>
+</template>
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+const paging = ref<any>(null);
+const list = ref<any[]>([]);
+const form = ref({
+    keyword: '',
+});
+const query = async (pageNum: number, pageSize: number) => {
+    const res = await useClientRequest.get('/plt-api/app/cpyVariety/pageList', {
+        ...form.value,
+        pageNum: pageNum,
+        pageSize: pageSize
+    });
+    if (res.code == 200) {
+        paging.value.complete(res.rows || []);
+    }
+};
+const checkedId = ref(null);
+const clickItem = (item: any) => {
+    checkedId.value = item.id;
+    uni.$emit('medicineSelected', item);
+    uni.navigateBack();
+};
+const onRefresh = () => {
+    try {
+        paging.value?.reload();
+    } catch (e) {
+        console.error('Error refreshing address list:', e);
+    }
+};
+</script>
+<style lang="scss" scoped>
+.select-item-card {
+    box-shadow: 0rpx 2rpx 8rpx rgba(0, 0, 0, 0.1);
+    border: 1rpx solid #e8e8e8;
+
+    &.active {
+        border-color: #4456fb;
+    }
+}
+</style>

+ 1 - 0
src/types/module.d.ts

@@ -9,5 +9,6 @@ declare module '@vue/runtime-core' {
     useDict: typeof useDict;
     selectDictLabel: typeof selectDictLabel;
     selectDictLabels: typeof selectDictLabels;
+   navigateBackOrHome: typeof navigateBackOrHome;
   }
 }

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
stats.html


Неке датотеке нису приказане због велике количине промена