张延森 4 yıl önce
ebeveyn
işleme
726d4cd7bb

+ 10
- 2
src/store/models/room.js Dosyayı Görüntüle

@@ -157,8 +157,6 @@ export default () => {
157 157
       url: '/room/save',
158 158
       data,
159 159
       toast: '请稍候...',
160
-    }).then(() => {
161
-      return
162 160
     })
163 161
   }
164 162
 
@@ -171,6 +169,15 @@ export default () => {
171 169
     })
172 170
   }
173 171
 
172
+  // 设置封面
173
+  const setRescCover = rescId => {
174
+    return request({
175
+      url: '/room/resc/cover',
176
+      params: { id: rescId },
177
+      toast: '请稍候...',
178
+    })
179
+  }
180
+
174 181
 
175 182
   return {
176 183
     list,
@@ -191,5 +198,6 @@ export default () => {
191 198
     closeHouse,
192 199
     houseEdit,
193 200
     getRescList,
201
+    setRescCover,
194 202
   }
195 203
 }

+ 4
- 0
src/utils/index.js Dosyayı Görüntüle

@@ -1,6 +1,10 @@
1 1
 
2 2
 import { Notify, Dialog } from 'vant'
3 3
 
4
+export function showSuccess(message) {
5
+  return Notify({ type: 'success', message, duration: 1000 })
6
+}
7
+
4 8
 export function showDanger(message) {
5 9
   return Notify({ type: 'danger', message })
6 10
 }

+ 1
- 1
src/utils/request/index.js Dosyayı Görüntüle

@@ -77,7 +77,7 @@ const handleError = type => error => {
77 77
   if (error.response) {
78 78
     console.error(`[${type}]:`)
79 79
     console.error(error.response)
80
-    showDanger(`错误的请求 - [${error.status}]`)
80
+    showDanger(`错误的请求 - [${error.status || error.message}]`)
81 81
   } else {
82 82
     const errorMessage = error.message || error.msg || error
83 83
     console.error(`[${type}] ${errorMessage}`)

+ 24
- 0
src/utils/uploadImage.js Dosyayı Görüntüle

@@ -0,0 +1,24 @@
1
+import { showDanger } from './index'
2
+import request from './request'
3
+
4
+export default (file, imgType) => {
5
+  const formData = new FormData()
6
+  formData.append('resourceImg', file)
7
+  formData.append('imgType', imgType)
8
+
9
+  return request({
10
+    url: '/upload-img',
11
+    data: formData,
12
+    toast: '请稍候...'
13
+  }).then(res => {
14
+    if (res.result) {
15
+      return res.filepath
16
+    } else {
17
+      showDanger(res.errMessage)
18
+    }
19
+  })
20
+  .catch(e => {
21
+    console.error(e)
22
+    showDanger(e.message)
23
+  })
24
+}

+ 175
- 0
src/view/resc/components/Items.vue Dosyayı Görüntüle

@@ -0,0 +1,175 @@
1
+<template>
2
+  <div>
3
+    <van-uploader
4
+      v-model="fileList"
5
+      :max-count="multiple ? 99 : 1"
6
+      :disabled="!canUpload"
7
+      :after-read="handleUpload"
8
+      :before-delete="handleDelete"
9
+    >
10
+      <template #preview-cover="item" >
11
+        <div class="resc-preview-hide" v-if="notAllowed">
12
+          <div style="width: 100%">
13
+            <span>上传人</span>:<br />
14
+            <span>{{item.raw.createName}}</span>
15
+          </div>
16
+        </div>
17
+        <div v-else-if="canSetCover">
18
+          <div class="resc-preview-tag" v-if="item.raw.imgTags === '1'">
19
+            <van-tag type="warning">主</van-tag>
20
+          </div>
21
+          <div v-else class="resc-preview-btn">
22
+            <van-button size="mini" type="warning" block @click.stop="handleCoverClick(item.raw)">设为封面</van-button>
23
+        </div>
24
+        </div>
25
+      </template>
26
+    </van-uploader>
27
+  </div>
28
+</template>
29
+
30
+<script>
31
+import { computed, onMounted } from 'vue'
32
+import { Uploader, Button, Tag } from 'vant'
33
+import { useModel } from '@zjxpcyc/vue-tiny-store'
34
+
35
+export default {
36
+  components: {
37
+    [Button.name]: Button,
38
+    [Tag.name]: Tag,
39
+    [Uploader.name]: Uploader,
40
+  },
41
+  
42
+  props: {
43
+    rescType: String,
44
+    limitFlag: String,
45
+    roomInfo: {
46
+      type: Object,
47
+      default: () => ({})
48
+    },
49
+    rescList: {
50
+      type: Array,
51
+      default: () => ([])
52
+    }
53
+  },
54
+
55
+  emits: ['cover', 'upload', 'delete'],
56
+
57
+  setup(props, { emit }) {
58
+    const { permissions, getPermission } = useModel('shiro')
59
+
60
+    const multiple = computed(() => {
61
+      return props.rescType - 0 > 1
62
+    })
63
+
64
+    const canSetCover = computed(() => {
65
+      return ['2', '3', '4'].includes(props.rescType)
66
+    })
67
+
68
+    // 看不到图
69
+    const notAllowed = computed(() => {
70
+      return props.rescType === '0' && !permissions['room:info:viewNum'] && !permissions['room:info:delResc']
71
+    })
72
+
73
+    // 是否允许删除图片
74
+    const canDelDesc = resc => {
75
+      const origin = resc.status === '0' && props.roomInfo?.status !== '7' && permissions['room:info:viewNum'] && permissions['room:info:delResc']
76
+      const nwd = !resc.id
77
+      return nwd || origin
78
+    }
79
+
80
+    // 是否允许上传图片
81
+    const canUpload = computed(() => {
82
+      const inProtected = props.limitFlag !== 'rescLimit' && props.roomInfo?.rescStatus === '9'
83
+      const validating = props.roomInfo?.rescStatus === '1'
84
+
85
+      return !inProtected && !validating
86
+    })
87
+
88
+    // 已上传列表
89
+    const fileList = computed({
90
+      get: () => {
91
+        return props.rescList.map((resc) => {
92
+          return {
93
+            url: notAllowed.value ? undefined : resc.url,
94
+            deletable: canDelDesc(resc),
95
+            raw: resc
96
+          }
97
+        })
98
+      },
99
+      set: val => {
100
+        console.log(val)
101
+      }
102
+    })
103
+
104
+    // 上传图片
105
+    const handleUpload = file => {
106
+      if (file && file.file) {
107
+        emit('upload', {file: file.file, type: props.rescType})
108
+      }
109
+    }
110
+
111
+    // 删除图片
112
+    const handleDelete = (file, detail) => {
113
+      emit('delete', {resc: file.raw, index: detail.index, rescType: props.rescType})
114
+    }
115
+
116
+    // 设为封面
117
+    const handleCoverClick = item => {
118
+      emit('cover', item)
119
+    }
120
+
121
+    onMounted(() => {
122
+      if (typeof permissions['room:info:viewNum'] !== 'boolean') {
123
+        getPermission('room:info:viewNum')
124
+      }
125
+
126
+      if (typeof permissions['room:info:delResc'] !== 'boolean') {
127
+        getPermission('room:info:delResc')
128
+      }
129
+    })
130
+    
131
+    return {
132
+      notAllowed,
133
+      multiple,
134
+      canSetCover,
135
+      fileList,
136
+      canUpload,
137
+      handleUpload,
138
+      handleDelete,
139
+      handleCoverClick,
140
+    }
141
+  }
142
+}
143
+</script>
144
+
145
+<style lang="less" scoped>
146
+.resc-preview-hide {
147
+  position: absolute;
148
+  width: 100%;
149
+  height: 100%;
150
+  background: #fff;
151
+  left: 0;
152
+  bottom: 0;
153
+  z-index: 100;
154
+  text-align: center;
155
+  font-size: .8em;
156
+  display: flex;
157
+  justify-items: center;
158
+  align-items: center;
159
+  line-height: 1.6em;
160
+}
161
+
162
+.resc-preview-btn {
163
+  position: absolute;
164
+  width: 100%;
165
+  left: 0;
166
+  bottom: 0;
167
+  z-index: 100;
168
+}
169
+
170
+.resc-preview-tag {
171
+  position: absolute;
172
+  left: 0;
173
+  top: 0;
174
+}
175
+</style>

+ 158
- 69
src/view/resc/index.vue Dosyayı Görüntüle

@@ -1,70 +1,99 @@
1 1
 <template>
2 2
   <x-loading x-id="room.resc.list">
3
-    <div class="resc">
4
-      <div class="mgtp" v-if="initData.limitFlag === 'rescLimit' && initData.rescStatus === '9'">
5
-        <p>房源录入后4小时内仅允许房源录入人上传图片,目前尚无权限上传实勘图</p>
6
-      </div>
7
-      <div class="mgtp" v-if="initData.rescStatus === '1'">
8
-        <p>当前实勘图正在审核中</p>
9
-      </div>
10
-      <div class="mgtp" v-if="initData.rescStatus === '0'">
11
-        <x-field label="实勘人">{{initData.rescUser}}</x-field>
12
-        <x-field label="达成时间">{{initData.rescTime}}</x-field>
13
-      </div>
14
-
15
-      <g-section title="门牌">
16
-        <van-uploader
17
-          v-model="houseNumberImg"
18
-          max-count="1"
19
-          :after-read="afterRead"
20
-        />
21
-      </g-section>
3
+    <div class="resc-mgtp" v-if="initData.limitFlag === 'rescLimit' && detail.roomInfo?.rescStatus === '9'">
4
+      <p>房源录入后4小时内仅允许房源录入人上传图片,目前尚无权限上传实勘图</p>
5
+    </div>
6
+    <div class="resc-mgtp" v-if="detail.roomInfo?.rescStatus === '1'">
7
+      <p>当前实勘图正在审核中</p>
8
+    </div>
9
+    <div class="resc-mgtp" v-if="detail.roomInfo?.rescStatus === '0'">
10
+      <x-field label="实勘人">{{initData.rescUser}}</x-field>
11
+      <x-field label="达成时间">{{initData.rescTime}}</x-field>
12
+    </div>
22 13
 
23
-      <g-section title="户型">
24
-        <van-uploader
25
-          v-model="houseNumberImg"
26
-          max-count="1"
27
-          :after-read="afterRead"
28
-        />
29
-      </g-section>
14
+    <div class="resc">
15
+      <van-row>
16
+        <van-col span="12">
17
+          <g-section title="门牌">
18
+            <RescItems
19
+              :room-info="detail.roomInfo"
20
+              :resc-list="initData.rescList?.[0]"
21
+              resc-type="0"
22
+              @upload="handleUpload"
23
+              @delete="handleDelete"
24
+            />
25
+          </g-section>
26
+        </van-col>
27
+        <van-col span="12">
28
+          <g-section title="户型">
29
+            <RescItems
30
+              :room-info="detail.roomInfo"
31
+              :resc-list="initData.rescList?.[1]"
32
+              resc-type="1"
33
+              @upload="handleUpload"
34
+              @delete="handleDelete"
35
+            />
36
+           </g-section>
37
+        </van-col>
38
+      </van-row>
30 39
 
31 40
       <g-section title="客厅">
32
-        <van-uploader
33
-          v-model="houseNumberImg"
34
-          :after-read="afterRead"
41
+        <RescItems
42
+          :room-info="detail.roomInfo"
43
+          :resc-list="initData.rescList?.[2]"
44
+          resc-type="2"
45
+          @cover="handleCover"
46
+          @upload="handleUpload"
47
+          @delete="handleDelete"
35 48
         />
36 49
       </g-section>
37 50
 
38 51
       <g-section title="卧室">
39
-        <van-uploader
40
-          v-model="houseNumberImg"
41
-          :after-read="afterRead"
52
+        <RescItems
53
+          :room-info="detail.roomInfo"
54
+          :resc-list="initData.rescList?.[3]"
55
+          resc-type="3"
56
+          @cover="handleCover"
57
+          @upload="handleUpload"
58
+          @delete="handleDelete"
42 59
         />
43 60
       </g-section>
44 61
 
45 62
       <g-section title="厨房">
46
-        <van-uploader
47
-          v-model="houseNumberImg"
48
-          :after-read="afterRead"
63
+        <RescItems
64
+          :room-info="detail.roomInfo"
65
+          :resc-list="initData.rescList?.[4]"
66
+          resc-type="4"
67
+          @cover="handleCover"
68
+          @upload="handleUpload"
69
+          @delete="handleDelete"
49 70
         />
50 71
       </g-section>
51 72
 
52 73
       <g-section title="卫生间">
53
-        <van-uploader
54
-          v-model="houseNumberImg"
55
-          :after-read="afterRead"
74
+        <RescItems
75
+          :room-info="detail.roomInfo"
76
+          :resc-list="initData.rescList?.[5]"
77
+          resc-type="5"
78
+          @cover="handleCover"
79
+          @upload="handleUpload"
80
+          @delete="handleDelete"
56 81
         />
57 82
       </g-section>
58 83
 
59 84
       <g-section title="其他">
60
-        <van-uploader
61
-          v-model="houseNumberImg"
62
-          :after-read="afterRead"
85
+        <RescItems
86
+          :room-info="detail.roomInfo"
87
+          :resc-list="initData.rescList?.[6]"
88
+          resc-type="6"
89
+          @cover="handleCover"
90
+          @upload="handleUpload"
91
+          @delete="handleDelete"
63 92
         />
64 93
       </g-section>
65 94
 
66 95
       <div style="margin-top: 2em">
67
-        <van-button block type="warning">
96
+        <van-button block type="warning" v-shiro="'room:info:addResc'">
68 97
           保存审核并提交
69 98
         </van-button>
70 99
       </div>
@@ -73,50 +102,110 @@
73 102
 </template>
74 103
 
75 104
 <script>
76
-import { ref } from "vue";
105
+import { onMounted, ref } from "vue";
77 106
 import { useRoute } from 'vue-router'
78 107
 import { useModel } from '@zjxpcyc/vue-tiny-store'
79 108
 //
80 109
 import {
110
+  Row,
111
+  Col,
81 112
   Uploader,
82 113
   Button,
83 114
 } from "vant"
84
-import { showDanger } from '@/utils';
115
+import RescItems from './components/Items'
116
+import { showDanger, showSuccess } from '@/utils'
117
+import uploadImage from '@/utils/uploadImage'
85 118
 
86 119
 export default {
87 120
   components: {
121
+    [Row.name]: Row,
122
+    [Col.name]: Col,
88 123
     [Uploader.name]: Uploader,
89 124
     [Button.name]: Button,
125
+    RescItems,
90 126
   },
91 127
 
92 128
   setup() {
93 129
     const initData = ref({})
94 130
     const route = useRoute()
95
-
96
-    const { getRescList } = useModel('room')
97
-
98
-    getRescList(route.query.roomId).then(res => {
99
-      initData.value = res
100
-    }).catch(e => {
101
-      showDanger(e.message)
131
+    const willSave = ref([])
132
+
133
+    const { detail, getRescList, getDetail, setRescCover } = useModel('room')
134
+
135
+    const roomId = route.query.roomId - 0
136
+
137
+    // 设置封面
138
+    const handleCover = resc => {
139
+      setRescCover(resc.id).then(() => {
140
+        (initData.value.rescList[resc.imgType] || []).forEach(it => {
141
+          if (it.id === resc.id) {
142
+            it.imgTags = '1'
143
+          } else {
144
+            it.imgTags = '0'
145
+          }
146
+        })
147
+
148
+        showSuccess('设置成功')
149
+      })
150
+    }
151
+
152
+    // 上传图片
153
+    const handleUpload = ({file, type}) => {
154
+      const sort = (initData.value.rescList[type] || []).length + willSave.value.filter(x => x.imgType === type).length
155
+
156
+      uploadImage(file, '1').then(url => {
157
+        const img = {
158
+          roomId,
159
+          url,
160
+          imgType: type,
161
+          sort
162
+        }
163
+
164
+        willSave.value.push(img)
165
+        initData.value = {
166
+          ...initData.value,
167
+          rescList: {
168
+            ...initData.value.rescList || {},
169
+            [type]: (initData.value.rescList[type] || []).concat(img)
170
+          }
171
+        }
172
+      })
173
+    }
174
+
175
+    // 删除图片
176
+    const handleDelete = ({resc, index, rescType}) => {
177
+      // 尚未保存
178
+      if (!resc.id) {
179
+        const list = initData.value.rescList[rescType] || []        
180
+        list.splice(index, 1)
181
+
182
+        initData.value = {
183
+          ...initData.value,
184
+          rescList: {
185
+            ...initData.value.rescList || {},
186
+            [rescType]: list
187
+          }
188
+        }
189
+      } else {
190
+        // 
191
+      }
192
+    }
193
+    
194
+    onMounted(() => {
195
+      getDetail(roomId)
196
+      getRescList(roomId).then(res => {
197
+        initData.value = res
198
+      }).catch(e => {
199
+        showDanger(e.message)
200
+      })
102 201
     })
103 202
 
104
-    const fileList = ref([
105
-      { url: "https://img.yzcdn.cn/vant/leaf.jpg" },
106
-      // Uploader 根据文件后缀来判断是否为图片文件
107
-      // 如果图片 URL 中不包含类型信息,可以添加 isImage 标记来声明
108
-      { url: "https://cloud-image", isImage: true },
109
-    ]);
110
-
111
-    const afterRead = (file) => {
112
-      // 此时可以自行将文件上传至服务器
113
-      console.log(file);
114
-    };
115
-
116 203
     return {
117 204
       initData,
118
-      fileList,
119
-      afterRead,
205
+      detail,
206
+      handleCover,
207
+      handleUpload,
208
+      handleDelete,
120 209
     };
121 210
   },
122 211
 };
@@ -125,11 +214,11 @@ export default {
125 214
 <!-- Add "scoped" attribute to limit CSS to this component only -->
126 215
 <style lang="less" scoped>
127 216
 .resc {
128
-  background: #fff;
129 217
   padding: 1em;
218
+}
130 219
 
131
-  .mgtp {
132
-    margin-top: 1em;
133
-  }
220
+.resc-mgtp {
221
+  margin-top: 1em;
134 222
 }
223
+
135 224
 </style>