plotDetails.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. <template>
  2. <view class="page-container">
  3. <!-- 基本信息区域 -->
  4. <view class="section-title">基本信息</view>
  5. <view class="form-list">
  6. <!-- 变更理由 -->
  7. <view class="form-item">
  8. <text class="label">变更理由*</text>
  9. <text class="value">{{ getDictLabel('bgly', detailData.changeReason) || '无' }}</text>
  10. </view>
  11. <!-- 地块编号 -->
  12. <view class="form-item">
  13. <text class="label">地块编号*</text>
  14. <text class="value">{{ detailData.dkbm || '无' }}</text>
  15. </view>
  16. <!-- 地块名称 -->
  17. <view class="form-item">
  18. <text class="label">地块名称</text>
  19. <text class="value">{{ detailData.dkmc || '无' }}</text>
  20. </view>
  21. <!-- 确权面积 -->
  22. <view class="form-item">
  23. <text class="label">确权面积*</text>
  24. <text class="value">{{ detailData.htmjm || 0 }} 亩</text>
  25. </view>
  26. <!-- 所有权性质 -->
  27. <view class="form-item">
  28. <text class="label">所有权性质*</text>
  29. <text class="value">{{ getDictLabel('syqxz', detailData.syqxz) || '无' }}</text>
  30. </view>
  31. <!-- 地块类别 -->
  32. <view class="form-item">
  33. <text class="label">地块类别*</text>
  34. <text class="value">{{ getDictLabel('dklb', detailData.dklb) || '无' }}</text>
  35. </view>
  36. <!-- 利用类型 -->
  37. <view class="form-item">
  38. <text class="label">利用类型*</text>
  39. <text class="value">{{ getDictLabel('lylx', detailData.tdlylx) || '无' }}</text>
  40. </view>
  41. <!-- 地力等级 -->
  42. <view class="form-item">
  43. <text class="label">地力等级*</text>
  44. <text class="value">{{ getDictLabel('dldj', detailData.dldj) || '无' }}</text>
  45. </view>
  46. <!-- 土地用途 -->
  47. <view class="form-item">
  48. <text class="label">土地用途</text>
  49. <text class="value">{{ getDictLabel('tdyt', detailData.tdyt) || '无' }}</text>
  50. </view>
  51. <!-- 基本农田 -->
  52. <view class="form-item">
  53. <text class="label">基本农田*</text>
  54. <text class="value">{{ getDictLabel('jbnt', detailData.sfjbnt) || '无' }}</text>
  55. </view>
  56. <!-- 地块东至 -->
  57. <view class="form-item">
  58. <text class="label">地块东至*</text>
  59. <text class="value">{{ detailData.dkdz || '无' }}</text>
  60. </view>
  61. <!-- 地块西至 -->
  62. <view class="form-item">
  63. <text class="label">地块西至*</text>
  64. <text class="value">{{ detailData.dkxz || '无' }}</text>
  65. </view>
  66. <!-- 地块南至 -->
  67. <view class="form-item">
  68. <text class="label">地块南至*</text>
  69. <text class="value">{{ detailData.dknz || '无' }}</text>
  70. </view>
  71. <!-- 地块北至 -->
  72. <view class="form-item">
  73. <text class="label">地块北至*</text>
  74. <text class="value">{{ detailData.dkbz || '无' }}</text>
  75. </view>
  76. <!-- 备注信息 -->
  77. <view class="form-item">
  78. <text class="label">备注信息</text>
  79. <text class="value">{{ detailData.remark || '无' }}</text>
  80. </view>
  81. <!-- 实测面积亩 -->
  82. <view class="form-item">
  83. <text class="label">实测面积亩</text>
  84. <text class="value">{{ tj_scmjm || 0 }} 亩</text>
  85. </view>
  86. <!-- 实测面积 ㎡ -->
  87. <view class="form-item">
  88. <text class="label">实测面积</text>
  89. <text class="value">{{ tj_scmj || 0 }} ㎡</text>
  90. </view>
  91. <!-- 范围选择 -->
  92. <view class="form-item">
  93. <text class="label">范围选择</text>
  94. <text class="value link" @click="viewRange">
  95. {{ hasLocalData ? '重新框选地块大致范围' : '框选地块大致范围' }}
  96. </text>
  97. </view>
  98. </view>
  99. <!-- 图片信息区域 -->
  100. <view class="section-title">图片信息</view>
  101. <view class="img-section">
  102. <text class="img-label">现场指界</text>
  103. <view class="img-list">
  104. <image
  105. v-for="(img, idx) in imageList.xczj.img"
  106. :key="idx"
  107. :src="img"
  108. class="img-preview"
  109. mode="widthFix"
  110. @click="previewImage(imageList.xczj.img, idx)"
  111. ></image>
  112. <text v-if="!imageList.xczj.img.length" class="no-data">暂无现场指界图片</text>
  113. </view>
  114. <text class="img-label mt-[20rpx]">附件资料</text>
  115. <view class="img-list">
  116. <image
  117. v-for="(img, idx) in imageList.fjzl.img"
  118. :key="idx"
  119. :src="img"
  120. class="img-preview"
  121. mode="widthFix"
  122. @click="previewImage(imageList.fjzl.img, idx)"
  123. ></image>
  124. <text v-if="!imageList.fjzl.img.length" class="no-data">暂无附件资料</text>
  125. </view>
  126. </view>
  127. </view>
  128. <view class="submit-btn" @click="handleSubmit">确定</view>
  129. </template>
  130. <script setup lang="ts">
  131. import { ref, computed, watch } from 'vue'
  132. import { onLoad,onShow } from '@dcloudio/uni-app';
  133. import { getdkxxxxData, getDictData,updateLandInfo } from '@/api/farmerApi.js';
  134. import { imgBaseURL } from '@/utils/request.js';
  135. // 详情数据
  136. const detailData = ref({})
  137. // 地块编号(接收页面参数)
  138. const xq_Dkbm = ref('')
  139. const xq_Cbfbm = ref('')
  140. const cd_List = ref({})
  141. // 图片列表
  142. const imageList = ref({
  143. xczj: { img: [], number: [] }, // 现场指界
  144. fjzl: { img: [], number: [] } // 附件资料
  145. })
  146. // 本地存储KEY(按地块编号区分)
  147. // const LOCAL_STORAGE_KEY = computed(() => `land_map_data_${xq_Dkbm.value}`)
  148. // 判断是否有本地数据(控制文字显示)
  149. const hasLocalData = ref(false)
  150. // ==================== 字典数据 ====================
  151. const dictData = ref<any>({
  152. bgly: [], // 变更理由
  153. syqxz: [], // 所有权性质
  154. dklb: [], // 地块类别
  155. dldj: [], // 地力等级
  156. tdyt: [], // 土地用途
  157. jbnt: [], // 基本农田
  158. lylx: [] // 利用类型
  159. })
  160. // 地图选择数据
  161. const coordinateData = ref<Array>([])
  162. const tj_scmjm = ref<number | string>(0) // 实测面积亩 → 默认 0
  163. const tj_scmj = ref<number | string>(0) // 实测面积㎡ → 默认 0
  164. // 字典格式转换
  165. const transformDictFormat = (originalDict : Record<string | number, string>) => {
  166. if (!originalDict || typeof originalDict !== 'object') return []
  167. return Object.entries(originalDict).map(([key, value]) => ({
  168. value: String(key),
  169. label: value as string
  170. }))
  171. }
  172. // 字典标签匹配
  173. const getDictLabel = (dictType : string, value : string | number | undefined) => {
  174. if (!value || !dictData.value[dictType]?.length) return ''
  175. const item = dictData.value[dictType].find((item : any) => String(item.value) === String(value))
  176. return item?.label || ''
  177. }
  178. // 加载字典数据
  179. const loadDictData = async () => {
  180. try {
  181. const [resBgly, resSyqxz, resDklb, resDldj, resTdyt, resJbnt, resLylx] = await Promise.all([
  182. getDictData('dic_bgly'),
  183. getDictData('dic_syqxz'),
  184. getDictData('dic_dklb'),
  185. getDictData('dic_dldj'),
  186. getDictData('dic_tdyt'),
  187. getDictData('dic_sf'),
  188. getDictData('dic_tdlylx')
  189. ])
  190. dictData.value.bgly = resBgly?.code === 200 ? transformDictFormat(resBgly.data) : []
  191. dictData.value.syqxz = resSyqxz?.code === 200 ? transformDictFormat(resSyqxz.data) : []
  192. dictData.value.dklb = resDklb?.code === 200 ? transformDictFormat(resDklb.data) : []
  193. dictData.value.dldj = resDldj?.code === 200 ? transformDictFormat(resDldj.data) : []
  194. dictData.value.tdyt = resTdyt?.code === 200 ? transformDictFormat(resTdyt.data) : []
  195. dictData.value.jbnt = resJbnt?.code === 200 ? transformDictFormat(resJbnt.data) : []
  196. dictData.value.lylx = resLylx?.code === 200 ? transformDictFormat(resLylx.data) : []
  197. } catch (err) {
  198. console.error('字典加载失败:', err)
  199. }
  200. }
  201. // ==================== 本地存储核心方法 ====================
  202. // 保存地图数据到本地
  203. const saveMapDataToLocal = (data) => {
  204. try {
  205. uni.setStorageSync('LOCAL_STORAGE_KEY', JSON.stringify(data));
  206. // uni.setStorageSync(LOCAL_STORAGE_KEY.value, JSON.stringify(data))
  207. // 保存后更新状态
  208. hasLocalData.value = true
  209. } catch (e) {
  210. console.error('保存地图数据失败', e)
  211. }
  212. }
  213. // 从本地获取地图数据
  214. const getMapDataFromLocal = () => {
  215. try {
  216. const data = uni.getStorageSync('LOCAL_STORAGE_KEY')
  217. return data ? JSON.parse(data) : null
  218. } catch (e) {
  219. console.error('获取地图数据失败', e)
  220. return null
  221. }
  222. }
  223. // 检查本地是否有数据
  224. const checkLocalData = () => {
  225. const localData = getMapDataFromLocal()
  226. hasLocalData.value = !!(localData && (localData.areaMu > 0 || localData.areaM2 > 0))
  227. }
  228. // 初始化:页面加载 → 读本地 → 有值显示,无值显示0
  229. const initLocalMapData = () => {
  230. const localData = getMapDataFromLocal()
  231. if (localData) {
  232. coordinateData.value = localData.points || []
  233. tj_scmjm.value = localData.areaMu || 0
  234. tj_scmj.value = localData.areaM2 || 0
  235. console.log('✅ 从本地加载实测数据:', localData)
  236. } else {
  237. // 无本地数据 → 重置为0
  238. coordinateData.value = []
  239. tj_scmjm.value = 0
  240. tj_scmj.value = 0
  241. }
  242. // 检查本地数据状态
  243. checkLocalData()
  244. }
  245. // ==================== 接口请求 & 数据绑定 ====================
  246. const getTotal = async (dkbm) => {
  247. try {
  248. uni.showLoading({ title: '加载中...' })
  249. const res = await getdkxxxxData({ dkbm: dkbm});
  250. uni.hideLoading()
  251. if (res.code === 200 && res.data?.length) {
  252. const item = res.data[0];
  253. xq_Cbfbm.value = item.cbdkxxTemp?.cbfbm || '';
  254. cd_List.value = item.dkTemp || {};
  255. detailData.value = { ...item.dkTemp }
  256. detailData.value.htmjm = item.cbdkxxTemp?.htmjm || 0;
  257. // 图片绑定
  258. const attachments = item.attachments || {}
  259. if (attachments.xczj?.length) {
  260. attachments.xczj.forEach((imgItem) => {
  261. imageList.value.xczj.img.push(imgBaseURL + imgItem.filePath)
  262. imageList.value.xczj.number.push(String(imgItem.id))
  263. })
  264. }
  265. if (attachments.fjzl?.length) {
  266. attachments.fjzl.forEach((imgItem) => {
  267. imageList.value.fjzl.img.push(imgBaseURL + imgItem.filePath)
  268. imageList.value.fjzl.number.push(String(imgItem.id))
  269. })
  270. }
  271. }
  272. } catch (e) {
  273. uni.hideLoading()
  274. uni.showToast({ title: '加载失败', icon: 'none' })
  275. console.error(e)
  276. }
  277. };
  278. // ==================== 页面方法 ====================
  279. // 查看地块范围
  280. const viewRange = () => {
  281. uni.navigateTo({
  282. url: `/pages/map/map?type=investigator&displayType=all&memberInfo=${encodeURIComponent(JSON.stringify(xq_Cbfbm.value))}`
  283. });
  284. }
  285. // 图片预览
  286. const previewImage = (urls, current) => {
  287. uni.previewImage({
  288. urls: urls,
  289. current: current
  290. })
  291. }
  292. // ==================== 提交 ====================
  293. const handleSubmit = async () => {
  294. if (!cd_List.value.bsm) {
  295. uni.showToast({ title: '数据异常,无法提交', icon: 'none' })
  296. return
  297. }
  298. const dkTemp = {
  299. bsm: cd_List.value.bsm || '',
  300. scmj: tj_scmj.value || 0,
  301. scmjm: tj_scmjm.value || 0,
  302. status: cd_List.value.status
  303. };
  304. const submitData = {
  305. dkTemp,
  306. geoJson: [coordinateData.value] || [],
  307. };
  308. uni.showLoading({ title: '提交中...' });
  309. try {
  310. const res = await updateLandInfo(submitData);
  311. if (res.code === 200) {
  312. uni.showToast({ title: '提交成功', icon: 'success' });
  313. setTimeout(() => {
  314. uni.navigateBack();
  315. }, 1500);
  316. } else {
  317. uni.showToast({ title: res.msg || '提交失败', icon: 'none' });
  318. }
  319. } catch (err) {
  320. uni.showToast({ title: '提交失败', icon: 'none' });
  321. } finally {
  322. uni.hideLoading();
  323. }
  324. };
  325. // ==================== 生命周期 ====================
  326. onLoad(async (options) => {
  327. xq_Dkbm.value = options.code || '';
  328. await loadDictData()
  329. await getTotal(xq_Dkbm.value);
  330. initLocalMapData(); // 加载本地存储数据
  331. });
  332. onShow(() => {
  333. const pages = getCurrentPages()
  334. const currentPage = pages[pages.length - 1]
  335. // 从地图返回 → 接收数据
  336. if (currentPage.$vm.selectedLandData) {
  337. const data = currentPage.$vm.selectedLandData
  338. console.log('✅ 地图返回实测数据:', data);
  339. // 赋值页面 → 实时显示
  340. coordinateData.value = data.points || [];
  341. tj_scmjm.value = data.areaMu;
  342. tj_scmj.value = data.areaM2;
  343. // 保存到本地
  344. saveMapDataToLocal(data)
  345. currentPage.$vm.selectedLandData = null
  346. }
  347. // 每次显示都检查本地数据状态
  348. checkLocalData()
  349. })
  350. </script>
  351. <style scoped>
  352. .page-container {
  353. padding: 16rpx;
  354. background-color: #f5f5f5;
  355. min-height: 100vh;
  356. }
  357. .section-title {
  358. font-size: 32rpx;
  359. font-weight: bold;
  360. margin-bottom: 16rpx;
  361. color: #333;
  362. }
  363. .form-list {
  364. background-color: #fff;
  365. border-radius: 12rpx;
  366. padding: 16rpx;
  367. margin-bottom: 16rpx;
  368. }
  369. .form-item {
  370. display: flex;
  371. justify-content: space-between;
  372. align-items: center;
  373. padding: 18rpx 0;
  374. border-bottom: 1px solid #eee;
  375. }
  376. .form-item:last-child {
  377. border-bottom: none;
  378. }
  379. .label {
  380. font-size: 28rpx;
  381. color: #666;
  382. }
  383. .value {
  384. font-size: 28rpx;
  385. color: #333;
  386. text-align: right;
  387. max-width: 60%;
  388. word-break: break-all;
  389. }
  390. .link {
  391. color: #409eff;
  392. }
  393. .img-section {
  394. background-color: #fff;
  395. border-radius: 12rpx;
  396. padding: 16rpx;
  397. }
  398. .img-label {
  399. font-size: 28rpx;
  400. color: #666;
  401. display: block;
  402. margin-bottom: 12rpx;
  403. }
  404. .img-list {
  405. display: flex;
  406. flex-wrap: wrap;
  407. gap: 12rpx;
  408. margin-bottom: 20rpx;
  409. }
  410. .img-preview {
  411. width: 220rpx;
  412. height: 220rpx;
  413. border-radius: 8rpx;
  414. background-color: #f5f5f5;
  415. }
  416. .no-data {
  417. font-size: 28rpx;
  418. color: #999;
  419. line-height: 220rpx;
  420. }
  421. .submit-btn {
  422. width: 80%;
  423. height: 90rpx;
  424. background-color: #409eff;
  425. color: #fff;
  426. font-size: 36rpx;
  427. border-radius: 45rpx;
  428. display: flex;
  429. align-items: center;
  430. justify-content: center;
  431. margin: 40rpx auto;
  432. box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3);
  433. }
  434. </style>