Browse Source

修改部分的接口

lisy 3 weeks ago
parent
commit
f0be689256

+ 1 - 0
package.json

@@ -57,6 +57,7 @@
         "clipboard": "^2.0.11",
         "dayjs": "^1.11.13",
         "pinia": "^2.0.36",
+        "pinia-plugin-persistedstate": "^4.7.1",
         "rollup-plugin-visualizer": "^6.0.3",
         "unplugin-auto-import": "^19.3.0",
         "uview-plus": "^3.6.4",

+ 24 - 0
pnpm-lock.yaml

@@ -68,6 +68,9 @@ importers:
       pinia:
         specifier: ^2.0.36
         version: 2.3.1(typescript@4.9.5)(vue@3.5.26(typescript@4.9.5))
+      pinia-plugin-persistedstate:
+        specifier: ^4.7.1
+        version: 4.7.1(pinia@2.3.1(typescript@4.9.5)(vue@3.5.26(typescript@4.9.5)))
       rollup-plugin-visualizer:
         specifier: ^6.0.3
         version: 6.0.5
@@ -3831,6 +3834,20 @@ packages:
     resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
     engines: {node: '>=0.10.0'}
 
+  pinia-plugin-persistedstate@4.7.1:
+    resolution: {integrity: sha512-WHOqh2esDlR3eAaknPbqXrkkj0D24h8shrDPqysgCFR6ghqP/fpFfJmMPJp0gETHsvrh9YNNg6dQfo2OEtDnIQ==}
+    peerDependencies:
+      '@nuxt/kit': '>=3.0.0'
+      '@pinia/nuxt': '>=0.10.0'
+      pinia: '>=3.0.0'
+    peerDependenciesMeta:
+      '@nuxt/kit':
+        optional: true
+      '@pinia/nuxt':
+        optional: true
+      pinia:
+        optional: true
+
   pinia@2.3.1:
     resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==}
     peerDependencies:
@@ -4681,6 +4698,7 @@ packages:
 
   whatwg-encoding@1.0.5:
     resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==}
+    deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
 
   whatwg-mimetype@2.3.0:
     resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==}
@@ -9625,6 +9643,12 @@ snapshots:
 
   pify@2.3.0: {}
 
+  pinia-plugin-persistedstate@4.7.1(pinia@2.3.1(typescript@4.9.5)(vue@3.5.26(typescript@4.9.5))):
+    dependencies:
+      defu: 6.1.4
+    optionalDependencies:
+      pinia: 2.3.1(typescript@4.9.5)(vue@3.5.26(typescript@4.9.5))
+
   pinia@2.3.1(typescript@4.9.5)(vue@3.5.26(typescript@4.9.5)):
     dependencies:
       '@vue/devtools-api': 6.6.4

+ 9 - 4
src/App.vue

@@ -2,10 +2,10 @@
 import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
 import { useAuthStore } from '@/store/modules/auth';
 import { autoLogin } from '@/utils/routeGuard';
-import { getToken, setToken, removeToken } from '@/utils/auth';
+import { useInfoStore } from '@/store'
+const infoStore = useInfoStore()
 onLaunch(async () => {
     console.log('App Launch');
-
     // 应用启动时检查登录状态
     try {
         // await autoLogin();
@@ -13,7 +13,13 @@ onLaunch(async () => {
         console.error('Auto login check failed:', error);
     }
 });
-setToken('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJhcHBfdXNlcjoxOTQwMjQ1NzU5Mjk2ODY0MjU3Iiwicm5TdHIiOiJiVllYa0QwVnY2T3JLNnc1d1ZOTlpiV0hFUTlhU1J2RyIsImNsaWVudGlkIjoiMjAyNTAyMTQiLCJvcGVuaWQiOiJva0NHMjRrU29nT2VWTGFkc1JVYm8tS2JqR2Y4IiwidXNlcklkIjoxOTQwMjQ1NzU5Mjk2ODY0MjU3fQ.-gNoaCFtXKHYtiGLdd5mpEyhBf9AZ9BTw9udNA_1feM')
+// 设置token并指定过期时间(例如24小时)
+console.log('设定token');
+
+infoStore.setToken('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJhcHBfdXNlcjoxOTQwMjQ1NzU5Mjk2ODY0MjU3Iiwicm5TdHIiOiJiVllYa0QwVnY2T3JLNnc1d1ZOTlpiV0hFUTlhU1J2RyIsImNsaWVudGlkIjoiMjAyNTAyMTQiLCJvcGVuaWQiOiJva0NHMjRrU29nT2VWTGFkc1JVYm8tS2JqR2Y4IiwidXNlcklkIjoxOTQwMjQ1NzU5Mjk2ODY0MjU3fQ.-gNoaCFtXKHYtiGLdd5mpEyhBf9AZ9BTw9udNA_1feM', 24 * 60 * 60 * 1000)
+console.log('获取用户信息,app');
+infoStore.getUserInfo()
+infoStore.getCompanyInfo()
 onShow(() => {
     console.log('App Show');
 });
@@ -25,7 +31,6 @@ onHide(() => {
 <style lang="scss">
 @import "uview-plus/index.scss";
 @import '@/assets/styles/public.scss';
-@import '@/assets/styles/common.scss';
 @import '@/assets/styles/uview-plus.scss';
 
 // 设置背景色

+ 0 - 276
src/assets/styles/common.scss

@@ -1,276 +0,0 @@
-.d-block {
-    display: block;
-}
-.navbar-logo {
-    width: 50rpx;
-    height: 50rpx;
-}
-
-.small-icon {
-    width: 38rpx;
-    height: 38rpx;
-}
-.base-icon {
-    width: 48rpx;
-    height: 48rpx;
-}
-.icon-36 {
-    width: 36rpx;
-    height: 36rpx;
-}
-.minn-icon {
-    width: 34rpx;
-    height: 34rpx;
-}
-.min-icon {
-    width: 30rpx;
-    height: 30rpx;
-}
-.small-icon-40 {
-    width: 40rpx;
-    height: 40rpx;
-}
-.active-hover {
-    opacity: 0.8;
-    cursor: pointer;
-}
-.base-page-banner {
-    position: absolute;
-    left: 0;
-    top: 0;
-    r: 0;
-    width: 100%;
-    z-index: -1;
-}
-.no-data-img {
-    width: 300rpx;
-    height: 300rpx;
-}
-.base-content {
-    padding: 24rpx;
-}
-.row-desc {
-    padding: 10rpx;
-    .row-lebal {
-        font-size: 30rpx;
-        color: #333;
-    }
-    .row-value {
-        padding: 30rpx 10rpx;
-        font-size: 30rpx;
-        color: #999;
-    }
-}
-
-.base-block {
-    border-radius: 10rpx;
-    background-color: #fff;
-}
-
-.b-r-c {
-    border-radius: 50%;
-}
-.b-radius {
-    border-radius: 16rpx;
-}
-.wl_bg {
-    position: absolute;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    width: 43rpx;
-    height: 87rpx;
-    margin: auto;
-    z-index: 2;
-}
-.radius-10 {
-    border-radius: 10rpx;
-}
-
-// 移动端底部安全区域
-.safe-area {
-    padding-bottom: constant(safe-area-inset-bottom);
-    padding-bottom: env(safe-area-inset-bottom);
-}
-
-.base-lh {
-    line-height: 1.6;
-}
-
-.u-primary-border {
-    border: 1rpx solid rgba($u-primary, 0.1);
-}
-// 数字字母从中间换行
-.break-word {
-    word-break: break-all;
-}
-
-.base-btm-wrap {
-    position: relative;
-    box-shadow: 6rpx 0px 27rpx 0px rgba($u-primary, 0.3);
-}
-
-.vip-content {
-    min-height: 100rpx;
-    // opacity: .1;
-}
-// 首行缩进
-.base-lh {
-    text-indent: 2em;
-}
-.home_icon {
-    width: 46rpx;
-    height: 46rpx;
-}
-// 超链接
-.base-underline {
-    text-decoration: underline;
-}
-// 底部样式
-.base-bottom-wrap {
-    position: relative;
-    box-shadow: 6rpx 0px 27rpx 0px rgba(#37A954, 0.3);
-    background-color: #fff;
-}
-
-.scroll-x-info {
-    white-space: nowrap;
-}
-.base-tag {
-    padding: 5rpx 12rpx;
-    border-radius: 6rpx;
-}
-.border-bottom-f5 {
-    border-bottom: 1px solid #f5f5f5;
-}
-.border-bottom-f2 {
-    border-bottom: 1px solid #f2f2f2;
-}
-.btm-shadow {
-    box-shadow: 5rpx 0px 13rpx 0px #adadad;
-}
-.pop-msg-box {
-    color: #ff6a07;
-    background-color: #fdf8e2;
-    border-radius: 8rpx;
-}
-.up-border {
-    transform: rotate(360deg);
-}
-
-.badge-num_base {
-    position: absolute;
-    left: 50%;
-    top: 6rpx;
-    transform: translateX(2rpx);
-}
-.fab-drop-shadow {
-    width: 132rpx;
-    height: 132rpx;
-}
-.flex-nowrap {
-    flex-wrap: nowrap;
-}
-.flex-shrink-0 {
-    flex-shrink: 0;
-}
-.left-icon-bg {
-    background-color: rgba(0, 0, 0, 0.3);
-    padding: 10rpx;
-    border-radius: 4rpx;
-}
-.dot-wrap2 {
-  position: absolute;
-  right: 10rpx;
-  bottom: 10rpx;
-  padding: 6rpx 10rpx;
-  background-color: rgba(0, 0, 0, 0.3);
-  border-radius: 4rpx;
-  color: #fff;
-  font-size: 26rpx;
-}
-.money-tag {
-  padding: 10rpx 20rpx;
-  font-size: 30rpx;
-  color: #fff;
-  line-height: 1;
-  background-color:#F4403B;
-  border-radius: 40rpx;
-}
-.ut-tag-primary {
-  padding: 2rpx 10rpx;
-  border-radius: 8rpx;
-  color: #fff;
-  font-size: 26rpx;
-  background-color: $u-primary;
-}
-.ut-tag-danger-plain {
-  padding: 2rpx 10rpx;
-  border-radius: 8rpx;
-  color: #F4403B;
-  font-size: 26rpx;
-  border: 1rpx solid #F4C6C4;
-}
-.ut-tag-info {
-  padding: 2rpx 10rpx;
-  border-radius: 8rpx;
-  color: #333;
-  font-size: 26rpx;
-  background-color: #F2F2F2;
-}
-.ut-tag-danger-plain-min {
-  padding: 2rpx 10rpx;
-  border-radius: 4rpx;
-  color: #F4403B;
-  font-size: 22rpx;
-  border: 1rpx solid #F4C6C4;
-  transform: rotate(360deg);
-}
-
-.btn-two-primary {
-    width: 500rpx;
-    height: 90rpx;
-    border-radius: 10rpx;
-    overflow: hidden;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    font-size: 36rpx;
-
-    .btn1 {
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        flex: 1;
-        height: 100%;
-        color: #37A954;
-        background-color: #D4E2DC;
-    }
-    .btn2 {
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        flex: 1;
-        height: 100%;
-        color: #FBE6A9;
-        background-color: #37A954;
-    }
-}
-
-// 超出两行省略
-.text-ellipsis-2 {
-    display: -webkit-box;
-    -webkit-box-orient: vertical;
-    -webkit-line-clamp: 2;
-    overflow: hidden;
-}
-
-.btm-wrap-shadow {
-    position: relative;
-    box-shadow: 6rpx 0px 27rpx 0px rgba(#37A954, 0.3);
-}
-.outview {
-    width: 100%;
-    max-width: 1000rpx;
-    height: 100vh;
-}

+ 7 - 0
src/assets/styles/public.scss

@@ -142,3 +142,10 @@ $colors: (
 .w-s-no {
     white-space: nowrap;
 }
+.radius-10 {
+    border-radius: 10rpx;
+}
+.home_icon{
+    width: 40rpx;
+    height: 40rpx;
+}

+ 4 - 1
src/components/ut-confirm-dialog/ut-confirm-dialog.vue

@@ -1,7 +1,7 @@
 // 如果up-popup弹框的遮罩层被覆盖或者是变为白色,需要查看unocss配置,unocss把u-popup__content—transition转化为两个变量了,需要过滤
 <template>
     <up-popup :show="internalShow" mode="center" :round="16" :closeable="false" @close="handleClose" bgColor="transparent">
-        <view class="confirm-dialog">
+        <view class="confirm-dialog" :style="{width}">
             <!-- 标题区域 -->
             <view class="dialog-header pd-32">
                 <text class="dialog-title f-s-32 f-w-6 c-#333">{{ title }}</text>
@@ -47,6 +47,8 @@ interface Props {
     confirmColor?: string;
     // 是否显示取消按钮
     showCancel?: boolean;
+    //弹框宽度
+    width?: string;
 }
 
 const props = withDefaults(defineProps<Props>(), {
@@ -60,6 +62,7 @@ const props = withDefaults(defineProps<Props>(), {
     confirmBgColor: '#37A954',
     confirmColor: '#fff',
     showCancel: true,
+    width: 'auto'
 });
 
 const emit = defineEmits<{

+ 4 - 3
src/main.ts

@@ -1,6 +1,6 @@
 import { createSSRApp } from 'vue';
 import App from './App.vue';
-import * as Pinia from 'pinia';
+import pinia from './store';
 import 'uno.css';
 import { selectDictLabel, selectDictLabels } from './utils/ruoyi';
 import { useDict } from '@/utils/dict';
@@ -35,7 +35,7 @@ const uviewProps: any = {
 };
 export function createApp() {
     const app = createSSRApp(App);
-    app.use(Pinia.createPinia());
+    app.use(pinia);
     // setConfig(uviewProps)
     app.use(uviewPlus, () => {
         return {
@@ -53,6 +53,7 @@ export function createApp() {
             '/tools/map-draw-area/index',
             '/plant/species/config/index',
             '/plant/base/gap-base-info/index',
+            '/plant/base/base-edit/index'
         ],
 
         // 自定义登录检查函数(返回 true 表示已登录)
@@ -79,6 +80,6 @@ export function createApp() {
     app.config.globalProperties.useDict = useDict;
     return {
         app,
-        Pinia,
+        Pinia: { pinia },
     };
 }

+ 129 - 35
src/pages/plant/index.vue

@@ -31,12 +31,12 @@
                     <view class="p-rtv d-flex a-c mb-6">
                         <view class="flex1 ov-hd f-s-32 c-333 d-flex a-ed">
                             <text class="mr-12 up-line-1 f-w-5">{{ name }}</text>
-                            <text class="c-999 f-s-24">{{ setCipByNum(phone, 3, 4) || '-' }}</text>
+                            <text class="c-999 f-s-24">{{ setCipByNum(phone ?? null, 3, 4) || '-' }}</text>
                         </view>
                     </view>
-                    <view class="f-s-22 mr-10 b-radius pt-4 pb-4 pl-10 pr-10 c-primary"
-                        style="width: max-content; background-color: #b7e8bc">
-                        {{ cpyname }}
+                    <view class="f-s-22 mr-10 radius-30 pt-4 pb-4 pl-10 pr-10 c-primary bg-#b7e8bc"
+                        style="width: max-content;">
+                        {{ currentCpyName }}
                     </view>
                 </view>
             </view>
@@ -80,7 +80,7 @@
                         </view>
                         <view class="d-flex a-c pt-20 pb-20 pl-16 pr-16 bg-#f7f7f7">
                             <view class="min-w-170 flex1">
-                                <ut-action-sheet v-model="form.type" :tabs="[{ label: '全部', value: '' }]"
+                                <ut-action-sheet v-model="form.queryType" :tabs="[{ label: '全部', value: '' }]"
                                     @change="onRefresh" title="选择原料类型">
                                     <view class="d-flex search-select-item a-c">
                                         <view class="flex1 ov-hd f-s-28 c-333 text-center f-w-5 w-s-no">{{ '全部' }}
@@ -92,7 +92,7 @@
                             </view>
                             <view class="h-86 pl-20 w-100%">
                                 <ut-search ref="searchRef" v-model="form.keyword" @search="changeSeach" margin="0"
-                                    :border="false" :placeholder="form.placeholder" bgColor="#fff" height="86rpx"
+                                    :border="false" placeholder="搜基地名称、编号、地址、负责人" bgColor="#fff" height="86rpx"
                                     borderRadius="10rpx"></ut-search>
                             </view>
                         </view>
@@ -100,43 +100,42 @@
                     <view class="pd-16">
                         <template>
                             <view v-for="(item, index) in list" :key="index" class="b-radius bg-#fff pd-20 mb-20">
-                                <view class="c-333 f-s-34 pd-5 f-w-5">德钦县拖顶乡洛沙村各加尼拉基地</view>
-                                <view class="c-ccc f-s-24 pd-5 pt-0">DQTDLSC00156768951001</view>
+                                <view class="c-333 f-s-34 pd-5 f-w-5">{{ item?.baseName }}</view>
+                                <view class="c-ccc f-s-24 pd-5 pt-0">{{ item?.baseCode }}</view>
                                 <view class="d-flex a-c">
                                     <view class="c-333 f-s-28 pd-5">
                                         <text class="c-#666">基地面积:</text>
-                                        <text class="f-w-5">12000亩</text>
+                                        <text class="f-w-5">{{ item?.gapInfo?.area || '-'}}</text>
                                     </view>
                                     <view class="flex1"></view>
                                     <view class="c-333 f-s-28 pd-5">
                                         <text class="c-#666">建设时间:</text>
-                                        <text class="f-w-5">2003年</text>
+                                        <text class="f-w-5">{{ item?.buildDate|| '-' }}</text>
                                     </view>
                                 </view>
                                 <view class="c-333 f-s-28 pd-5">
                                     <text class="c-#666">基地地址:</text>
-                                    <text class="f-w-5">云南省红河州个旧市卡房镇田心村小田心村268号</text>
+                                    <text class="f-w-5">{{ item?.gapInfo?.address|| '-' }}</text>
                                 </view>
                                 <view class="c-333 f-s-28 pd-5 d-flex">
                                     <text class="c-#666 w-s-no">当前在地品种:</text>
-                                    <text
-                                        class="ov-hd tx-ov w-s-no f-w-5">三七、天麻、徐长卿、白及、徐长卿、白及、三七、天麻、徐长卿、白及、徐长卿、白及</text>
-                                    <text class="flex1 w-s-no f-w-5">等120个品种</text>
+                                    <text class="ov-hd tx-ov w-s-no f-w-5">{{item.plantingVarieties?.map(items => items.variety).join('、') || '-'}}</text>
+                                    <text v-if="item.plantingVarieties?.length" class="flex1 w-s-no f-w-5">等{{item.plantingVarieties?.length}}个品种</text>
                                 </view>
                                 <view class="pd-10"></view>
                                 <view class="p-rtv">
                                     <up-image width="100%"
-                                        src="https://img1.baidu.com/it/u=436536502,2810995452&fm=253&fmt=auto&app=120&f=JPEG?w=820&h=500"
+                                        :src="item.gapInfo?.basePic"
                                         mode="widthFix"> </up-image>
                                     <view class="pl-20 pr-20 pt-10 pb-10 bg-#00000080 c-#ccc f-s-20"
                                         style="position: absolute; bottom: 140rpx; right: 0; border-radius: 10rpx 0 0 10rpx">
-                                        李思思负责</view>
+                                        {{item?.contactName}}负责</view>
                                     <view class="pl-20 pr-20 pt-10 pb-10 bg-#00000080 c-#ccc f-s-20"
                                         style="position: absolute; bottom: 80rpx; right: 0; border-radius: 10rpx 0 0 10rpx">
                                         公司+合作社</view>
                                     <view class="pl-20 pr-20 pt-10 pb-10 bg-#00000080 c-#ccc f-s-20"
                                         style="position: absolute; bottom: 20rpx; right: 0; border-radius: 10rpx 0 0 10rpx">
-                                        经度:E64.63 纬度:N27.7385</view>
+                                        经度:E{{ item?.gapInfo?.lng }} 纬度:N{{ item?.gapInfo?.lat }}</view>
                                 </view>
                             </view>
                         </template>
@@ -153,29 +152,112 @@
             </view>
         </template>
     </z-paging>
+    <ut-confirm-dialog v-model:show="showDeleteDialog" width="80vw" title="请选择要添加到基地类型" :confirmText="'确认选择'" :cancelText="'取消'" @confirm="handlechoseConfirm" @cancel="handleDeleteCancel">
+        <view class="" v-for="item in pt_base_type" :key="item?.value">
+            <view style="border: 1rpx solid;" :style="{'backgroundColor': item?.value == basetype ? '#EBF6EE' : '#f7f7f7','borderColor':item?.value == basetype ? '#37A954' : 'transparent'}" class="pr-30 d-flex a-c mb-20 radius-100" @click="handlechose(item.value)" >
+                <view class="radius-50% mg-8">
+                    <up-avatar size="90rpx":src="item?.avatar || 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/avatar.png'" class="mr-20"></up-avatar>
+                </view>
+                <view class="c-#333 f-s-34">
+                    {{ item?.label }}
+                </view>
+                <view class="flex1"></view>
+                <view class="d-flex">
+                    <img v-if="basetype === item.value" class="w-30 h-30" src="/static/images/plant/chooseSuccessfully.png" mode="widthFix" alt="" />
+                </view>
+            </view>
+        </view>
+    </ut-confirm-dialog>
 </template>
 <script setup lang="ts">
 import { useClientRequest } from '@/utils/request';
 import { setCipByNum } from '@/utils/public';
-interface navbar {
-    bottom: number;
-    height: number;
-    left: number;
-    right: number;
-    top: number;
-    width: number;
-    id: string;
-    dataset?: any
+import { useInfoStore } from '@/store'
+import { computed,ref } from 'vue';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { pt_base_type } = toRefs<any>(proxy?.useDict('pt_base_type'));
+const infoStore = useInfoStore()
+// 获取用户信息
+const avatar = computed(() => infoStore.userInfo?.avatar || '')
+const name = computed(() => infoStore.userInfo?.name || '')
+const phone = computed(() => infoStore.userInfo?.phone || '')
+const currentCpyName = computed(() => infoStore.userInfo?.currentCpyName || '')
+// 证书文件类型
+interface CertFile {
+  fileName: string;
+  url: string;
+  fileSize: number;
+}
+// 差异信息类型
+interface GapInfo {
+  id: number;
+  sourceType: string;
+  gapBaseName: string;
+  sn: string;
+  medicineName: string;
+  medicineId: number;
+  area: number;
+  basePic: string;
+  lng: number;
+  lat: number;
+  adcode: string;
+  address: string;
+  ratedDate: string; // 格式: "YYYY-MM-DD"
+  certFile: CertFile[];
+  res: string;
+  auditor: number;
+  msg: string;
+}
+
+// 种植品种类型
+interface PlantingVariety {
+  baseId: number;
+  varietyId: string;
+  variety: string;
+}
+
+// 坐标点类型
+interface Coordinate {
+  lng: number;
+  lat: number;
+}
+
+// 主数据类型
+interface BaseData {
+  id: number;
+  baseName: string;
+  baseCode?: string;
+  baseType?: string;
+  adcode?: string;
+  buildDate?: string; // 格式: "YYYY-MM-DD"
+  orgType: string;
+  contactId: number;
+  contactTel: string;
+  contactName?:string
+  lng: number;
+  lat: number;
+  basePic: string;
+  address: string;
+  area: number;
+  gapFlag: string;
+  gapInfo: GapInfo;
+  cpyid: number;
+  appid: number;
+  partnerId: number;
+  createBy: number;
+  updateBy: number;
+  createTime: string; // ISO 8601 格式
+  updateTime: string; // ISO 8601 格式
+  hide: string;
+  plantingVarieties: PlantingVariety[];
+  coordinates: Coordinate[][]; // 二维坐标数组
 }
 const instance = getCurrentInstance();
-const list = ref([]);
+const list = ref<BaseData[]>();
 const paging = ref();
 const bubble = ref(uni.getMenuButtonBoundingClientRect());
-const avatar = ref();
-const name = ref('神奇大侠');
-const phone = ref('17708862791');
-const cpyname = ref('智慧溯源有限公司');
-const form = ref({ type: '', placeholder: '搜基地名称、编号、地址、负责人', keyword: '' });
+
+const form = ref({ queryType: '',  keyword: '' });
 const speciesArray = ref([]);
 const navBarBgColor = ref('transparent');
 const stickyTop = ref(0);
@@ -200,7 +282,6 @@ const query = async (pageNum: number, pageSize: number) => {
         ...form.value,
     };
     const res = await useClientRequest.get('/plt-api/app/base/pageList', params);
-    console.log(res);
     const { rows } = res;
     paging.value.complete(rows);
 };
@@ -208,13 +289,26 @@ const query = async (pageNum: number, pageSize: number) => {
 const getSpecies = async () => {
     const res = await useClientRequest.get('/plt-api/app/cpyVariety/list');
     if (res.code === 200) {
-        console.log(res);
         speciesArray.value = res.data.map((item) => item.varietyName)
     }
 };
+const showDeleteDialog = ref(true);
+const basetype = ref();
+const handlechose = (item:string) => {
+    basetype.value = item;
+};
+
+// 处理删除取消
+const handleDeleteCancel = () => {
+    showDeleteDialog.value = false;
+    basetype.value = null;
+};
+const handlechoseConfirm = ()=>{
+    uni.$u.route({ type: 'navigateTo', url: '/plant/base/base-edit/index' ,params: { basetype: basetype.value} })
+}
 
 onMounted(() => {
-    const querys = uni.createSelectorQuery().in(instance.proxy);
+    const querys = uni.createSelectorQuery().in(instance?.proxy);
     querys
         .select('#topup-navbar')
         .boundingClientRect((data: any) => {

+ 9 - 6
src/store/index.ts

@@ -1,9 +1,12 @@
 import { createPinia } from 'pinia';
+import { createPersistedState } from 'pinia-plugin-persistedstate';
+const pinia = createPinia();
+pinia.use(createPersistedState());
 
-const store = createPinia();
+export default pinia;
 
-export { store };
-
-export * from './modules/dict';
-export * from './modules/user';
-export * from './modules/auth';
+// 显式导出以避免命名冲突
+export { useDictStore } from './modules/dict';
+export { useUserStore, type UserInfo as UserInfoType, type UserProfile } from './modules/user';
+export { useAuthStore, type LoginForm, type LoginResponse } from './modules/auth';
+export { useInfoStore } from './modules/info';

+ 160 - 0
src/store/modules/info.ts

@@ -0,0 +1,160 @@
+import { useClientRequest } from '@/utils/request'
+import { defineStore } from 'pinia'
+import { ref } from 'vue'
+import { UserInfoOptional,CompanyInfoData } from '../type/infoType'
+import type { StorageLike } from 'pinia-plugin-persistedstate'
+// 为 UniApp 创建适配的 storage(与 store/index.ts 保持一致)
+const uniStorage: StorageLike = {
+  getItem: (key: string): string | null => {
+    try {
+      return uni.getStorageSync(key);
+    } catch (error) {
+      console.error('读取存储失败:', error);
+      return null;
+    }
+  },
+  setItem: (key: string, value: string): void => {
+    try {
+      uni.setStorageSync(key, value);
+    } catch (error) {
+      console.error('写入存储失败:', error);
+    }
+  },
+};
+// Token存储键和默认过期时间(24小时)
+const TOKEN_STORAGE_KEY = 'pinia_token_with_expire'
+const DEFAULT_TOKEN_EXPIRE = 24 * 60 * 60 * 1000  // 24小时(毫秒)
+const INFOSTORE_KEY = 'info-store'
+export const useInfoStore = defineStore('infoStore', () => {
+    // token
+    const token = ref('')
+    //从存储中读取token并检查是否过期
+    const getTokenFromStorage = (): string => {
+        try {
+            const stored = uni.getStorageSync(TOKEN_STORAGE_KEY)
+            console.log(stored,'stored');
+            if (!stored) return ''
+            const tokenData = JSON.parse(stored)
+            const { value, timestamp, expire } = tokenData
+            // 检查是否过期
+            if (expire && Date.now() - timestamp > expire) {
+                uni.removeStorageSync(TOKEN_STORAGE_KEY)
+                return ''
+            }
+            return value
+        } catch (error) {
+            console.error('读取token失败:', error)
+            return ''
+        }
+    }
+    /**
+     * 设置token,可指定过期时间(毫秒)
+     * @param value token值
+     * @param expireMs 过期时间(毫秒),默认24小时
+     */
+    const setToken = (value: string, expireMs: number = DEFAULT_TOKEN_EXPIRE) => {
+        token.value = value
+        // 存储带过期时间的token
+        const tokenData = {
+            value,
+            timestamp: Date.now(),
+            expire: expireMs
+        }
+        uni.setStorageSync(TOKEN_STORAGE_KEY, JSON.stringify(tokenData))
+    }
+    //移除token
+    
+    const removeToken = () => {
+        token.value = ''
+        uni.removeStorageSync(TOKEN_STORAGE_KEY)
+        // 移除token,并删除其他缓存数据
+        uni.removeStorageSync(INFOSTORE_KEY)
+    }
+    // 检查token是否过期
+    const isTokenExpired = (): boolean => {
+        try {
+            const stored = uni.getStorageSync(TOKEN_STORAGE_KEY)
+            if (!stored) return true
+            const tokenData = JSON.parse(stored)
+            const { timestamp, expire } = tokenData
+            // 如果没有设置过期时间,则永不过期
+            if (!expire) return false
+            return Date.now() - timestamp > expire
+        } catch {
+            return true
+        }
+    }
+
+    // 获取token剩余有效时间(毫秒)
+    const getTokenRemainingTime = (): number => {
+        try {
+            const stored = uni.getStorageSync(TOKEN_STORAGE_KEY)
+            if (!stored) return 0
+
+            const tokenData = JSON.parse(stored)
+            const { timestamp, expire } = tokenData
+
+            if (!expire) return Infinity
+
+            const elapsed = Date.now() - timestamp
+            const remaining = expire - elapsed
+
+            return remaining > 0 ? remaining : 0
+        } catch {
+            return 0
+        }
+    }
+    // 初始化时从存储读取token
+    token.value = getTokenFromStorage()
+    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+    // 用户信息
+    const userInfo = ref<UserInfoOptional | null>(null)
+    // 获取用户信息
+    const getUserInfo = async (): Promise<UserInfoOptional | null> => {
+        try {
+            const { data } = await useClientRequest.get('/app/auth/getUserInfo')
+            userInfo.value = data
+            return data
+        } catch (error) {
+            console.error('获取用户信息失败:', error)
+            return null
+        }
+    }
+    // 清除用户信息
+    const clearUserInfo = (): void => {
+        userInfo.value = null
+    }
+    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+    //公司信息
+    const companyInfo = ref<CompanyInfoData | null>(null)
+    // 获取公司信息
+    const getCompanyInfo = async (): Promise<CompanyInfoData | null> => {
+        try {
+            const { data } = await useClientRequest.get(`/app/company/currentCpyDetail`)
+            companyInfo.value = data
+            return data
+        } catch (error) {
+            console.error('获取公司信息失败:', error)
+            return null
+        }
+    }
+    return {
+        token,
+        setToken,
+        removeToken,
+        isTokenExpired,
+        getTokenRemainingTime,
+        userInfo,
+        getUserInfo,
+        clearUserInfo,
+        companyInfo,
+        getCompanyInfo,
+    }
+}, {
+    // 启用持久化,但只持久化 userInfo,其中token使用自定义的带过期时间的存储逻辑
+    persist: {
+        key: INFOSTORE_KEY,
+        storage: uniStorage,
+        pick:['userInfo','companyInfo']
+    }
+})

+ 94 - 0
src/store/type/infoType.ts

@@ -0,0 +1,94 @@
+export interface UserInfoOptional {
+  adcode?: string | null;
+  adcodeName?: string | null;
+  avatar?: string | null;
+  bindCpyRes?: string | null;
+  certCount?: number | null;
+  cpyNames?: string[] | null;
+  createBy?: string | null;
+  createTime?: string | null;
+  currentCardId?: string | null;
+  currentCpyName?: string | null;
+  currentCpyid?: string | null;
+  currentCreditCode?: string | null;
+  email?: string | null;
+  expertPersonId?: string | null;
+  functions?: string[] | null;
+  id?: string | null;
+  idcard?: string | null;
+  isExpertPerson?: string | null;
+  name?: string | null;
+  nickName?: string | null;
+  openid?: string | null;
+  phone?: string | null;
+  postName?: string | null;
+  pwdStatus?: string | null;
+  roles?: string[] | null;
+  status?: string | null;
+  tenantId?: string | null;
+  unionid?: string | null;
+  updateTime?: string | null;
+  vipEnd?: string | null;
+  vipFlag?: string | null;
+  vipStart?: string | null;
+  wxBindStauts?: string | null;
+  wxbind?: string | null;
+}
+interface LicenseInfo {
+  url: string;
+  fileName: string;
+  fileType: string | null;
+  fileSize: string | null;
+  pureFileName: string;
+}
+export interface CompanyInfoData{
+    id: string | null;
+  cpySn: string | null;
+  cpyName: string | null;
+  tel: string | null;
+  creditCode: string | null;
+  status: string | null;
+  authStatus: string | null;
+  adcdCode: string | null;
+  storePhoto: string | null;
+  address: string | null;
+  contactPerson: string | null;
+  currentTel: string | null;
+  currentPerson: string | null;
+  adminId: string | null;
+  adminName: string | null;
+  res: string | null;
+  bindMsg: string | null;
+  joinPartner: string | null;
+  partnerId: number | null;
+  partnerName: string | null;
+  userid: string | null;
+  createBy: string | null;
+  license: LicenseInfo | null;
+  cpyType: string | null;
+  purposeApp: string | null;
+  fieldApplyId: string | null;
+  userType: string | null;
+  operatorName: string | null;
+  operateType: string | null;
+  allStatus: string | null;
+  application: any[] | null;
+  certSpecial: any[] | null;
+  adcdCodeName: string | null;
+  adminPhone: string | null;
+  adminAvatar: string | null;
+  certBase: any[] | null;
+  createTime: string | null;
+  updateTime: string | null;
+  postCode: string | null;
+  bindStatus: string | null;
+  cpyResMsg: string | null;
+  integrate: string | null;
+  extraInfo: ExtraInfo | null;
+  hasAdmin: string | null;
+  lastLoginInfo: any | null;
+  supervisionType: string | null;
+  supervisionArea: string | null;
+  supervisionAreaName: string | null;
+  integrateApp: any[] | null;
+}

+ 2 - 2
src/utils/public.ts

@@ -60,9 +60,9 @@ export function goLogin(): void {
     });
 }
 
-export const setCipByNum = (val: string, startNum: number, num: number, isCip: boolean = false): string => {
+export const setCipByNum = (val: string | null, startNum: number, num: number, isCip: boolean = false): string => {
     if (isCip) {
-        return val;
+        return val || '-';
     }
     if (!val) return '-';
     const a = val.slice(0, startNum);

+ 110 - 11
src/utils/request.ts

@@ -1,4 +1,8 @@
 import config from '@/config';
+import { useInfoStore } from '@/store'
+import { getCurrentPage } from '@/utils/public';
+import { recursiveDecodeURIComponent } from '@/utils/ruoyi'
+import errorCode from '@/utils/errorCode'
 const { clientId, appid } = config;
 // uniapp封装的请求方法
 let timeout = 60 * 1000;
@@ -7,16 +11,38 @@ let timeout = 60 * 1000;
 const getHeader = () => {
     let header = {
         'Content-Type': 'application/json',
-        Authorization: 'Bearer ' + uni.getStorageSync('token') || '',
-        'xid':config?.appid || '',
-        'clientId':config?.clientId || '',
+        Authorization: 'Bearer ' + useInfoStore().token || '',
+        'xid': config?.appid || '',
+        'clientId': config?.clientId || '',
     };
     return header;
 };
 
 // 获取host地址
-export const request = ({ url, method = 'GET', data = {}, header = null }: any) => {
+export const request = ({ url, method = 'GET', data = {}, isToken, header = null }: any) => {
     const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000';
+    if (isToken && !useInfoStore().isTokenExpired()) {
+        uni.hideLoading()
+        useInfoStore().removeToken()
+        let fullPath = recursiveDecodeURIComponent(getCurrentPage()?.$page?.fullPath)
+        const isLoginPage = recursiveDecodeURIComponent(fullPath).indexOf('/pages/login/login') !== -1;
+        if (isLoginPage) {
+            return;
+        }
+        const fulllpathParams = fullPath.split('?');
+        const fullpathstr = fulllpathParams.length > 1 ? `${fulllpathParams[0]}?${fulllpathParams[fulllpathParams.length - 1]}` : fulllpathParams[0];
+        // 获取当前页面路径
+        uni.$u.route({
+            type: 'redirect',
+            url: '/pages/login/login',
+            params: {
+                // 转成浏览器可识别的字符串
+                // 这里可以传递当前页面的路径作为参数,方便登录后重定向回原页面
+                redirect: encodeURIComponent(fullpathstr)
+            }
+        })
+        return
+    }
     return new Promise((resolve, reject) => {
         uni.request({
             url: baseUrl + url,
@@ -24,13 +50,86 @@ export const request = ({ url, method = 'GET', data = {}, header = null }: any)
             data,
             timeout: timeout,
             header: header || getHeader(),
-            success: (res: any) => {
-                resolve(res.data);
-            },
-            fail: (err) => {
-                reject(err);
-            },
-        });
+        }).then((response) => {
+            let { data, statusCode } = response
+            console.log(statusCode, 'statusCode');
+
+            if (statusCode !== 200) {
+                uni.showToast({
+                    icon: 'none',
+                    title: '后端接口连接异常'
+                })
+                reject('后端接口连接异常')
+                return
+            }
+            const code = (data as any).code || 200
+            const msg = errorCode[code] || (data as any).msg || errorCode['default']
+            // 处理业务错误
+            if (code !== 200) {
+                uni.showToast({
+                    icon: 'none',
+                    title: msg
+                })
+                reject(msg)
+                return
+            }
+            if (code === 401) {
+                uni.hideLoading()
+                useInfoStore().removeToken()
+                let fullPath = recursiveDecodeURIComponent(getCurrentPage()?.$page?.fullPath)
+                const isLoginPage = recursiveDecodeURIComponent(fullPath).indexOf('/pages/login/login') !== -1;
+                if (isLoginPage) {
+                    return;
+                }
+                const fulllpathParams = fullPath.split('?');
+                const fullpathstr = fulllpathParams.length > 1 ? `${fulllpathParams[0]}?${fulllpathParams[fulllpathParams.length - 1]}` : fulllpathParams[0];
+                // 获取当前页面路径
+                uni.$u.route({
+                    type: 'redirect',
+                    url: '/pages/login/login',
+                    params: {
+                        // 转成浏览器可识别的字符串
+                        // 这里可以传递当前页面的路径作为参数,方便登录后重定向回原页面
+                        redirect: encodeURIComponent(fullpathstr)
+                    }
+                })
+                return reject('无效的会话,或者会话已过期,请重新登录。')
+            } else if (code === 500) {
+                uni.hideLoading()
+                if (msg) {
+                    uni.showToast({
+                        title: msg,
+                        icon: 'none'
+                    });
+
+                }
+                return reject('500')
+            } else if (code !== 200) {
+                uni.hideLoading()
+                uni.showToast({
+                    title: msg,
+                    icon: 'none'
+                });
+                reject(code)
+            }
+            // 成功情况
+            resolve(data)
+        }).catch(error => {
+            let { message } = error
+            if (message === 'Network Error') {
+                message = '后端接口连接异常'
+            } else if (message.includes('timeout')) {
+                message = '系统接口请求超时'
+            } else if (message.includes('Request failed with status code')) {
+                message = '系统接口' + message.substr(message.length - 3) + '异常'
+            }
+            uni.hideLoading()
+            uni.showToast({
+                title: message,
+                icon: 'none'
+            });
+            return reject(error)
+        })
     });
 };
 export const useClientRequest = {

+ 64 - 0
src/utils/ruoyi.ts

@@ -347,3 +347,67 @@ export const getFileSuffix = (fileName: string): string => {
     const lastDotIndex = fileName.lastIndexOf('.');
     return lastDotIndex !== -1 ? fileName.substring(lastDotIndex + 1) : '';
 };
+export const recursiveDecode = (input: string, maxDepth: number = 10): string => {
+    if (typeof input !== 'string' || input.length === 0) return input;
+    
+    let prev: string = input;
+    
+    for (let i = 0; i < maxDepth; i++) {
+        let decoded: string;
+        try {
+            // 先替换 '+' 为 ' '(常见 form 编码场景),再解码
+            decoded = decodeURIComponent(prev.replace(/\+/g, ' '));
+        } catch (e) {
+            // 非法序列或无法解码,停止
+            break;
+        }
+        if (decoded === prev) break;
+        prev = decoded;
+    }
+    
+    return prev;
+};
+
+// 递归解码对象的类型
+type RecursiveDecodeResult<T> = T extends string 
+    ? string 
+    : T extends Array<infer U> 
+        ? Array<RecursiveDecodeResult<U>> 
+        : T extends object 
+            ? { [K in keyof T]: RecursiveDecodeResult<T[K]> } 
+            : T;
+
+export const recursiveDecodeURIComponent = <T>(obj: T): RecursiveDecodeResult<T> => {
+    if (typeof obj === 'string') {
+        return recursiveDecode(obj) as RecursiveDecodeResult<T>;
+    } else if (Array.isArray(obj)) {
+        return obj.map((item) => recursiveDecodeURIComponent(item)) as RecursiveDecodeResult<T>;
+    } else if (typeof obj === 'object' && obj !== null) {
+        const decodedObj: Record<string, any> = {};
+        for (const key in obj) {
+            if (Object.prototype.hasOwnProperty.call(obj, key)) {
+                decodedObj[key] = recursiveDecodeURIComponent((obj as Record<string, any>)[key]);
+            }
+        }
+        return decodedObj as RecursiveDecodeResult<T>;
+    }
+    return obj as RecursiveDecodeResult<T>;
+};
+
+// 或者使用更简单的类型定义,保持函数简洁
+export const recursiveDecodeURIComponentSimple = (obj: any): any => {
+    if (typeof obj === 'string') {
+        return recursiveDecode(obj);
+    } else if (Array.isArray(obj)) {
+        return obj.map((item) => recursiveDecodeURIComponentSimple(item));
+    } else if (typeof obj === 'object' && obj !== null) {
+        const decodedObj: Record<string, any> = {};
+        for (const key in obj) {
+            if (Object.prototype.hasOwnProperty.call(obj, key)) {
+                decodedObj[key] = recursiveDecodeURIComponentSimple(obj[key]);
+            }
+        }
+        return decodedObj;
+    }
+    return obj;
+};

File diff suppressed because it is too large
+ 2 - 0
stats.html


+ 3 - 7
unocss.config.js

@@ -5,6 +5,7 @@ export default defineConfig({
     shortcuts: [
         {
             center: 'flex justify-center items-center',
+            'b-radius': 'radius-16',
         },
     ],
     rules: [
@@ -91,6 +92,8 @@ export default defineConfig({
                 'background-color': `rgba(0, 0, 0, ${num})`,
             }),
         ],
+        [/^radius-([\.\d]+)$/, ([_, num]) => ({ 'border-radius': `${num}rpx` })],
+        [/^radius-([\.\d]+)%$/, ([_, num]) => ({ 'border-radius': `${num}%` })],
         // 透明度
         [
             /^opacity-([\.\d]+)$/,
@@ -127,13 +130,6 @@ export default defineConfig({
         [/^min-h-([\.\d]+)$/, ([_, num]) => ({ 'min-height': `${num}rpx` })],
         // 栅格 30份
         [/^hcol-([\.\d]+)$/, ([_, num]) => ({ width: `${(+num / 30) * 100}%` })],
-        // border-radius-8
-        [
-            /^border-radius-([\.\d]+)$/,
-            ([_, num]) => ({
-                'border-radius': `${num}rpx`,
-            }),
-        ],
         // border-w-4
         [
             /^border-w-([\.\d]+)$/,

Some files were not shown because too many files changed in this diff