index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. <template>
  2. <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" @query="query" @scroll="onPageScroll" safe-area-inset-bottom>
  3. <template #top>
  4. <up-navbar :fixed="true" :bgColor="navBarBgColor">
  5. <template #left>
  6. <view class="d-flex a-c pb-5" id="topup-navbar" :style="{ width: `${bubble.left - 30}px` }">
  7. <image class="home_icon mr-20" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/home.png" mode="widthFix" />
  8. <text class="f-s-40 c-333 f-w-5 w-s-no">中药材种植全链条追溯</text>
  9. <view class="flex1"></view>
  10. </view>
  11. </template>
  12. </up-navbar>
  13. </template>
  14. <view class="h-500 w-100%" style="background: linear-gradient(to left, #d2f7d5, #eafad8); position: absolute; top: 0; left: 0; z-index: -1"> </view>
  15. <template>
  16. <up-navbar :fixed="false" bgColor="transparent">
  17. <template #left>
  18. <view class="pd-10"></view>
  19. </template>
  20. </up-navbar>
  21. <view class="user-page-header pd-10 d-flex a-c mg-14 p-rtv">
  22. <view class="user-page-header-avatar mr-20 p-rtv">
  23. <up-avatar size="116rpx" :src="avatar || 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/avatar.png'"></up-avatar>
  24. </view>
  25. <view class="flex1 ov-hd mr-40">
  26. <view class="p-rtv d-flex a-c mb-6">
  27. <view class="flex1 ov-hd f-s-32 c-333 d-flex a-ed">
  28. <text class="mr-12 up-line-1 f-w-5">{{ name }}</text>
  29. <text class="c-999 f-s-24">{{ setCipByNum(phone ?? null, 3, 4) || '-' }}</text>
  30. </view>
  31. </view>
  32. <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">
  33. {{ currentCpyName }}
  34. </view>
  35. </view>
  36. </view>
  37. </template>
  38. <template>
  39. <view class="p-rtv">
  40. <view class="pd-10 mg-14">
  41. <view class="b-radius pd-6" style="border: 1rpx solid #fff; background: linear-gradient(90deg, #c1f3c5 0%, rgba(193, 243, 197, 0.5) 20%, rgba(255, 255, 255, 0.5) 35%, rgba(255, 255, 255, 0.5) 50%, rgba(232, 255, 234, 0.5) 100%, #e8ffea 100%), linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.3) 30%, rgba(255, 255, 255, 0.3) 80%, transparent 100%)">
  42. <view class="b-radius pd-10 p-rtv" style="border: 1rpx solid #baedbf">
  43. <image class="w-200" src="/static/images/plant/typeofBusiness.png" mode="widthFix" style="position: absolute; top: 10rpx; left: 10rpx" />
  44. <view v-if="!speciesArray.length" class="pd-20"></view>
  45. <view v-if="speciesArray.length" class="d-flex pr-15">
  46. <view class="flex1"></view>
  47. <view class="f-s-22 c-primary" @click="$u.route({ url: '/plant/species/config/index' })">去修改{{ '>' }}</view>
  48. </view>
  49. <view v-if="speciesArray.length" class="c-#333 f-s-24 d-flex pl-40 pr-15 pb-15 pt-15">
  50. <view class="ov-hd tx-ov w-s-no">{{ speciesArray.join('、') }}</view>
  51. <view v-if="speciesArray.length > 4" class="flex1 w-s-no">等{{ speciesArray.length }}个品种 </view>
  52. </view>
  53. <view v-if="!speciesArray.length" @click="$u.route({ url: '/plant/species/config/index' })" class="c-primary bg-#E3F6E7 f-s-22 mg-at radius-10 w-250 h-50 d-flex a-c j-c"> 暂未配置品种,去配置{{ '>' }}</view>
  54. <view v-if="!speciesArray.length" class="pd-7"></view>
  55. </view>
  56. </view>
  57. </view>
  58. <view class="b-radius pt-0 bg-#f7f7f7" style="border: 1rpx solid #fff; border-bottom-color: transparent; margin-top: -40rpx">
  59. <up-sticky :offset-top="stickyTop">
  60. <view class="d-flex a-c pd-16 p-rtv">
  61. <view class="c-333 f-s-32 f-w-5 z-index-1">基地与地块管理</view>
  62. <image class="w-230" src="/static/images/plant/BasePlotManagement.png" mode="widthFix" style="position: absolute; top: 44rpx; left: 16rpx; z-index: 0" />
  63. <view class="flex1"></view>
  64. <view @click="$u.route({ url: '/plant/base/gap-base-info/index' })" class="c-primary f-s-22 z-index-1">GAP基地获评信息管理{{ '>' }}</view>
  65. <image src="/static/images/plant/basePlotBG.png" class="w-100%" mode="widthFix" style="position: absolute; top: 0; left: 0; z-index: -1"></image>
  66. </view>
  67. <view class="d-flex a-c pt-20 pb-20 pl-16 pr-16 bg-#f7f7f7">
  68. <view class="min-w-170 flex1">
  69. <ut-action-sheet v-model="form.queryType" :tabs="[{ label: '全部', value: '' }]" @change="onRefresh" title="选择原料类型">
  70. <view class="d-flex search-select-item a-c">
  71. <view class="flex1 ov-hd f-s-28 c-333 text-center f-w-5 w-s-no">{{ '全部' }} </view>
  72. <up-icon size="24rpx" color="#333" name="arrow-down-fill" class="mr-5"></up-icon>
  73. </view>
  74. </ut-action-sheet>
  75. </view>
  76. <view class="h-86 pl-20 w-100%">
  77. <ut-search ref="searchRef" v-model="form.keyword" @search="changeSeach" margin="0" :border="false" placeholder="搜基地名称、编号、地址、负责人" bgColor="#fff" height="86rpx" borderRadius="10rpx"></ut-search>
  78. </view>
  79. </view>
  80. </up-sticky>
  81. <view class="pd-16">
  82. <template>
  83. <view v-for="(item, index) in list" :key="index" class="b-radius bg-#fff pd-20 mb-20">
  84. <view class="c-333 f-s-34 pd-5 f-w-5">{{ item?.baseName }}</view>
  85. <view class="c-ccc f-s-24 pd-5 pt-0">{{ item?.baseCode }}</view>
  86. <view class="d-flex a-c">
  87. <view class="c-333 f-s-28 pd-5">
  88. <text class="c-#666">基地面积:</text>
  89. <text class="f-w-5">{{ item?.gapInfo?.area || '-' }}</text>
  90. </view>
  91. <view class="flex1"></view>
  92. <view class="c-333 f-s-28 pd-5">
  93. <text class="c-#666">建设时间:</text>
  94. <text class="f-w-5">{{ item?.buildDate || '-' }}</text>
  95. </view>
  96. </view>
  97. <view class="c-333 f-s-28 pd-5">
  98. <text class="c-#666">基地地址:</text>
  99. <text class="f-w-5">{{ item?.gapInfo?.address || '-' }}</text>
  100. </view>
  101. <view class="c-333 f-s-28 pd-5 d-flex">
  102. <text class="c-#666 w-s-no">当前在地品种:</text>
  103. <text class="ov-hd tx-ov w-s-no f-w-5">{{ item.plantingVarieties?.map((items) => items.variety).join('、') || '-' }}</text>
  104. <text v-if="item.plantingVarieties?.length" class="flex1 w-s-no f-w-5">等{{ item.plantingVarieties?.length }}个品种</text>
  105. </view>
  106. <view class="pd-10"></view>
  107. <view class="p-rtv">
  108. <up-image width="100%" :src="item.gapInfo?.basePic" mode="widthFix"> </up-image>
  109. <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"> {{ item?.contactName }}负责</view>
  110. <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>
  111. <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"> 经度:E{{ item?.gapInfo?.lng }} 纬度:N{{ item?.gapInfo?.lat }}</view>
  112. </view>
  113. </view>
  114. </template>
  115. </view>
  116. </view>
  117. </view>
  118. </template>
  119. <template #empty>
  120. <view class="" style="margin-top: -200rpx">
  121. <ut-empty class="mg-at" color="#ccc" size="28rpx" image="/static/images/plant/noEmptyBase.png">尚未添加绘制种养殖基地信息~</ut-empty>
  122. <view class="b-radius c-#fff f-s-36 bg-#37A954 h-78 w-382 d-flex a-c j-c mg-at" @click="showDeleteDialog = true">
  123. <img class="w-38 h-36 mr-10" src="/static/images/plant/chooseGAP.png" alt="" mode="widthFix" />
  124. <text>去添加基地</text>
  125. </view>
  126. </view>
  127. </template>
  128. <view class="h-210" v-if="list?.length"></view>
  129. <view v-if="list?.length" :style="{ height: `${safeAreaBottom}px` }"></view>
  130. <template #bottom>
  131. <ut-tabar activeTab="base"></ut-tabar>
  132. </template>
  133. </z-paging>
  134. <ut-confirm-dialog v-model:show="showDeleteDialog" width="80vw" title="请选择要添加到基地类型" :confirmText="'确认选择'" :cancelText="'取消'" @confirm="handlechoseConfirm" @cancel="handleDeleteCancel">
  135. <view class="" v-for="item in pt_base_type" :key="item?.value">
  136. <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)">
  137. <view class="radius-50% mg-8">
  138. <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>
  139. </view>
  140. <view class="c-#333 f-s-34">
  141. {{ item?.label }}
  142. </view>
  143. <view class="flex1"></view>
  144. <view class="d-flex">
  145. <img v-if="basetype === item.value" class="w-30 h-30" src="/static/images/plant/chooseSuccessfully.png" mode="widthFix" alt="" />
  146. </view>
  147. </view>
  148. </view>
  149. </ut-confirm-dialog>
  150. <ut-suspension v-if="sus?.left" :imageWidth="60" :imageHeight="60" :x="sus?.left" :y="sus?.bottom" :inertia="false" :snap-threshold="40">
  151. <image src="/static/images/plant/addBase.png" mode="widthFix" class="w-120 h-120" @click="showDeleteDialog = true"></image>
  152. </ut-suspension>
  153. </template>
  154. <script setup lang="ts">
  155. import { useClientRequest } from '@/utils/request';
  156. import { setCipByNum } from '@/utils/public';
  157. import { useInfoStore } from '@/store';
  158. import { computed, ref } from 'vue';
  159. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  160. const { pt_base_type } = toRefs<any>(proxy?.useDict('pt_base_type'));
  161. const infoStore = useInfoStore();
  162. // 获取用户信息
  163. const avatar = computed(() => infoStore.userInfo?.avatar || '');
  164. const name = computed(() => infoStore.userInfo?.name || '');
  165. const phone = computed(() => infoStore.userInfo?.phone || '');
  166. const currentCpyName = computed(() => infoStore.userInfo?.currentCpyName || '');
  167. const windowInfo = uni.getWindowInfo();
  168. const safeAreaBottom = windowInfo.safeAreaInsets.bottom;
  169. // 证书文件类型
  170. interface CertFile {
  171. fileName: string;
  172. url: string;
  173. fileSize: number;
  174. }
  175. // 差异信息类型
  176. interface GapInfo {
  177. id: number;
  178. sourceType: string;
  179. gapBaseName: string;
  180. sn: string;
  181. medicineName: string;
  182. medicineId: number;
  183. area: number;
  184. basePic: string;
  185. lng: number;
  186. lat: number;
  187. adcode: string;
  188. address: string;
  189. ratedDate: string; // 格式: "YYYY-MM-DD"
  190. certFile: CertFile[];
  191. res: string;
  192. auditor: number;
  193. msg: string;
  194. }
  195. // 种植品种类型
  196. interface PlantingVariety {
  197. baseId: number;
  198. varietyId: string;
  199. variety: string;
  200. }
  201. // 坐标点类型
  202. interface Coordinate {
  203. lng: number;
  204. lat: number;
  205. }
  206. // 主数据类型
  207. interface BaseData {
  208. id: number;
  209. baseName: string;
  210. baseCode?: string;
  211. baseType?: string;
  212. adcode?: string;
  213. buildDate?: string; // 格式: "YYYY-MM-DD"
  214. orgType: string;
  215. contactId: number;
  216. contactTel: string;
  217. contactName?: string;
  218. lng: number;
  219. lat: number;
  220. basePic: string;
  221. address: string;
  222. area: number;
  223. gapFlag: string;
  224. gapInfo: GapInfo;
  225. cpyid: number;
  226. appid: number;
  227. partnerId: number;
  228. createBy: number;
  229. updateBy: number;
  230. createTime: string; // ISO 8601 格式
  231. updateTime: string; // ISO 8601 格式
  232. hide: string;
  233. plantingVarieties: PlantingVariety[];
  234. coordinates: Coordinate[][]; // 二维坐标数组
  235. }
  236. const instance = getCurrentInstance();
  237. const list = ref<BaseData[]>();
  238. const paging = ref();
  239. const bubble = ref(uni.getMenuButtonBoundingClientRect());
  240. const form = ref({ queryType: '', keyword: '' });
  241. const speciesArray = ref([]);
  242. const navBarBgColor = ref('transparent');
  243. const stickyTop = ref(0);
  244. const systemInfo = uni.getSystemInfoSync();
  245. const sus = ref({
  246. left: 0,
  247. bottom: 0,
  248. });
  249. sus.value.left = systemInfo.windowWidth - 10;
  250. sus.value.bottom = systemInfo.windowHeight - 200;
  251. const changeSeach = () => {
  252. paging.value.reload();
  253. };
  254. const onRefresh = () => {
  255. paging.value.reload();
  256. };
  257. const onPageScroll = (e: any) => {
  258. const { scrollTop } = e.detail;
  259. if (scrollTop > 20) {
  260. navBarBgColor.value = '#d9f8d6';
  261. } else {
  262. navBarBgColor.value = 'transparent';
  263. }
  264. };
  265. const query = async (pageNum: number, pageSize: number) => {
  266. const params = {
  267. pageNum,
  268. pageSize,
  269. ...form.value,
  270. };
  271. const res = await useClientRequest.get('/plt-api/app/base/pageList', params);
  272. console.log(res, 'res');
  273. if (res) {
  274. const { rows } = res;
  275. paging.value.complete(rows);
  276. }
  277. };
  278. // 查询企业的种植品种
  279. const getSpecies = async () => {
  280. const res = await useClientRequest.get('/plt-api/app/cpyVariety/list');
  281. if (res?.code === 200) {
  282. speciesArray.value = res.data?.map((item: any) => item.medicineName);
  283. }
  284. };
  285. const showDeleteDialog = ref(false);
  286. const basetype = ref();
  287. const handlechose = (item: string) => {
  288. basetype.value = item;
  289. };
  290. // 处理删除取消
  291. const handleDeleteCancel = () => {
  292. showDeleteDialog.value = false;
  293. basetype.value = null;
  294. };
  295. const handlechoseConfirm = () => {
  296. uni.$u.route({ type: 'navigateTo', url: '/plant/base/base-edit/index', params: { basetype: basetype.value } });
  297. };
  298. onMounted(() => {
  299. const querys = uni.createSelectorQuery().in(instance?.proxy);
  300. querys
  301. .select('#topup-navbar')
  302. .boundingClientRect((data: any) => {
  303. console.log(data);
  304. stickyTop.value = data.top + data.height;
  305. })
  306. .exec();
  307. getSpecies();
  308. });
  309. onShow(() => {
  310. getSpecies();
  311. });
  312. </script>
  313. <style lang="scss" scoped>
  314. // @import '@/assets/styles/theme.scss';
  315. .search-select-item {
  316. height: 86rpx;
  317. background-color: #fff;
  318. border-radius: 10rpx;
  319. box-sizing: border-box;
  320. padding-left: 16rpx;
  321. padding-right: 16rpx;
  322. padding-top: 14rpx;
  323. padding-bottom: 14rpx;
  324. }
  325. </style>