index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. <route lang="json">
  2. {
  3. "style": {
  4. "navigationBarTitleText": "个人动态",
  5. "navigationBarBackgroundColor": "#fff"
  6. }
  7. }
  8. </route>
  9. <script setup lang="ts">
  10. import SectionHeading from '@/components/section-heading.vue'
  11. import { createCircle, getByDictType } from '../../../core/libs/requests'
  12. import { useUserStore } from '../../../store'
  13. import { storeToRefs } from 'pinia'
  14. import { useToast } from 'wot-design-uni'
  15. import { CircleType, DictType } from '../../../core/libs/models'
  16. import DataForm from '@/components/data-form.vue'
  17. import { zipToObject } from 'radash'
  18. import { useRouter } from '../../../core/utils/router'
  19. import BottomAppBar from '@/components/bottom-app-bar.vue'
  20. import dragImg from '@/components/drag-img/drag-img.vue'
  21. import { requestToast, toast } from '../../../core/utils/common'
  22. import { messages } from '../../../core/libs/messages'
  23. import { DataFormSchema } from '../../../components/data-form'
  24. import { ComponentExposed } from 'vue-component-type-helpers'
  25. import { AnalysisEventType, useAnalysis } from '@/composables/analysis'
  26. import { resolve } from 'dns'
  27. const { report } = useAnalysis(false)
  28. const router = useRouter()
  29. const userStore = useUserStore()
  30. const { userInfo } = storeToRefs(userStore)
  31. const { error } = useToast()
  32. const circleType = ref<CircleType>()
  33. const content = ref('')
  34. const fileList = ref([])
  35. const action = ref(`${import.meta.env.VITE_SERVER_BASEURL}/app-api/infra/file/upload`)
  36. const dataFormRef = ref<ComponentExposed<typeof DataForm>>()
  37. const schema = ref<DataFormSchema>({
  38. caseName: {
  39. label: '案例名称:',
  40. type: 'TextField',
  41. required: true,
  42. labelWidth: 80,
  43. props: { placeholder: '填写案例位置/名称' },
  44. },
  45. spaceType: {
  46. label: '空间类别:',
  47. type: 'Select',
  48. required: true,
  49. labelWidth: 80,
  50. props: {
  51. placeholder: '选择',
  52. columns: [],
  53. },
  54. },
  55. designStyle: {
  56. label: '设计风格:',
  57. type: 'Select',
  58. required: true,
  59. labelWidth: 80,
  60. props: { columns: [], placeholder: '选择' },
  61. },
  62. // spaceAddr: { label: '空间位置', type: 'TextField' },
  63. spaceExtent: {
  64. label: '空间面积:',
  65. type: 'TextField',
  66. required: true,
  67. labelWidth: 80,
  68. props: { placeholder: '填写面积' },
  69. },
  70. circleDesc: {
  71. label: '案例描述:',
  72. type: 'Textarea',
  73. required: true,
  74. labelWidth: 80,
  75. props: { placeholder: '请简单描述您的案例和设计理念', maxlength: 500 },
  76. },
  77. // customerDemand: { label: '客户需求', type: 'TextField' },
  78. })
  79. const rules = {
  80. caseName: [{ required: true, message: '请填写案例名称' }],
  81. spaceType: [{ required: true, message: '请选择空间类别' }],
  82. designStyle: [{ required: true, message: '请选择设计风格' }],
  83. spaceExtent: [{ required: true, message: '请填写空间面积' }],
  84. circleDesc: [{ required: true, message: '请填写案例描述' }],
  85. }
  86. const useImg = ref(true)
  87. const useVideo = ref(true)
  88. const formData = ref({})
  89. const formInited = ref(false)
  90. const tagName = ref('')
  91. const tagIds = ref([])
  92. const imgList = ref([])
  93. const publishing = ref(false)
  94. const delImg = (index:number) =>{
  95. fileList.value = imgList.value
  96. }
  97. const sortChange = () =>{
  98. console.log('sort')
  99. fileList.value = imgList.value
  100. }
  101. const handleChange = ({ fileList: files }) => {
  102. console.log(files)
  103. let arr = [];
  104. // for(let i in files){
  105. // if(files[i].status==="success"){
  106. // arr.push(files[i])
  107. // }
  108. // }
  109. fileList.value = files
  110. imgList.value = files
  111. if(files.length > 0){
  112. useVideo.value = false
  113. }else{
  114. useVideo.value = true
  115. }
  116. }
  117. const handleVideoChange = ({ fileList: files }) => {
  118. fileList.value = files
  119. if(files.length > 0){
  120. useImg.value = false
  121. }else{
  122. useImg.value = true
  123. }
  124. // console.log(imgList.value)
  125. }
  126. const uploadImg = async (img) =>{
  127. return new Promise((resolve)=>{
  128. uni.uploadFile({
  129. url:action.value,
  130. filePath: img,
  131. name:img,
  132. success: (res) => {
  133. // console.log(res)
  134. resolve(res)
  135. }
  136. })
  137. })
  138. }
  139. const handleSubmit = async () => {
  140. if (circleType.value === CircleType.case) {
  141. const { valid, errors } = await dataFormRef.value.validate()
  142. console.log(valid, errors)
  143. if (!valid) {
  144. return false
  145. }
  146. }
  147. // if (!imgList.value.length) {
  148. // toast(messages.moment.imageNotExist)
  149. // return false
  150. // }
  151. // console.log(imgList.value)
  152. // let imgUrl = [];
  153. // for(let i in imgList.value){
  154. // let res = await uploadImg(imgList.value[i])
  155. // console.log(res)
  156. // imgUrl.push()
  157. // }
  158. // console.log(imgUrl)
  159. // return false
  160. if(useImg.value){
  161. if (!imgList.value.length) {
  162. toast(messages.moment.imageNotExist)
  163. return false
  164. }
  165. }else{
  166. if (!fileList.value.length) {
  167. toast(messages.moment.imageNotExist)
  168. return false
  169. }
  170. }
  171. publishing.value = true
  172. const { code, msg, duration } = await requestToast(
  173. () =>
  174. createCircle({
  175. stylistId: userInfo.value.userId,
  176. stylistName: userInfo.value.nickname,
  177. bannerUrls: useImg.value?imgList.value.map(({ response }) => JSON.parse(response).data):fileList.value.map(({ response }) => JSON.parse(response).data),
  178. tagName: tagName.value,
  179. headUrl: userInfo.value.avatar,
  180. circleDesc: content.value,
  181. circleType: circleType.value,
  182. tagIds: tagIds.value,
  183. ...formData.value,
  184. }),
  185. { success: true, successTitle: '发布成功' },
  186. )
  187. if (code === 0) {
  188. setTimeout(() => {
  189. publishing.value = false
  190. router.back()
  191. }, duration)
  192. await report(AnalysisEventType.PublishCircle)
  193. // publishing.value = false
  194. // router.back()
  195. }
  196. }
  197. const updateTagName = (options: { tagNames: string[]; tagIds: string[] }) => {
  198. if (options.tagNames.length === 0) {
  199. tagName.value = ''
  200. return
  201. }
  202. tagName.value = options.tagNames.join(',')
  203. tagIds.value = options.tagIds
  204. }
  205. onMounted(() => {
  206. uni.$on('updateTagName', updateTagName)
  207. })
  208. onUnmounted(() => {
  209. uni.$off('updateTagName', updateTagName)
  210. })
  211. onLoad(async (query: { circleType: '1' | '2' }) => {
  212. circleType.value = query.circleType as CircleType
  213. await uni.setNavigationBarTitle({ title: { '1': '个人动态', '2': '设计案例' }[circleType.value] })
  214. const optionsSchema = {
  215. designStyle: getByDictType(DictType.memberDesignStyle).then(({ data }) => data),
  216. spaceType: getByDictType(DictType.circleSpaceType).then(({ data }) => data),
  217. }
  218. const res = zipToObject(
  219. Object.keys(optionsSchema),
  220. await Promise.all(Object.values(optionsSchema)),
  221. )
  222. schema.value.designStyle.props.columns = res.designStyle
  223. schema.value.spaceType.props.columns = res.spaceType
  224. formInited.value = true
  225. })
  226. </script>
  227. <template>
  228. <div class="flex-grow bg-white p-3.5 flex flex-col">
  229. <template v-if="circleType === CircleType.case && formInited">
  230. <DataForm
  231. ref="dataFormRef"
  232. v-model="formData"
  233. :schema="schema"
  234. :rules="rules"
  235. direction="horizontal"
  236. ></DataForm>
  237. </template>
  238. <template v-if="circleType === CircleType.moment">
  239. <wd-textarea v-model="content" placeholder="分享你此刻的想法" />
  240. </template>
  241. <!-- <div class="flex items-center">
  242. <img
  243. class="w-[100px] h-[100px] rounded-lg overflow-hidden"
  244. src="https://via.placeholder.com/100x100"
  245. />
  246. <div class="w-[100px] h-[100px] bg-[#f3f3f3] justify-center items-center inline-flex">
  247. <div class="w-7 h-7 relative flex-col justify-start items-start flex"></div>
  248. </div>
  249. </div> -->
  250. <div v-if="circleType === '2'" class="flex items-center">
  251. <span class="text-[#ef4343] text-base font-normal font-['PingFang_SC'] leading-normal">
  252. *
  253. </span>
  254. <SectionHeading
  255. title="案例图片:"
  256. subtitle="首图建议尺寸1125x1104,最多可上传30张"
  257. size="base"
  258. custom-class="my-5"
  259. ></SectionHeading>
  260. </div>
  261. <div class="flex">
  262. <div class="mr-[20rpx]" v-if="useImg">
  263. <wd-upload
  264. :file-list="fileList"
  265. image-mode="aspectFill"
  266. accept="image"
  267. :action="action"
  268. :multiple="true"
  269. :limit="String(circleType) === '2' ? 30 : 9"
  270. @change="handleChange"
  271. ></wd-upload>
  272. <div class="text-[24rpx] text-black/60 text-center">上传图片</div>
  273. </div>
  274. <div v-if="useVideo && String(circleType) === '1'">
  275. <wd-upload
  276. :file-list="fileList"
  277. image-mode="aspectFill"
  278. accept="video"
  279. :action="action"
  280. :limit="1"
  281. @change="handleVideoChange"
  282. ></wd-upload>
  283. <div class="text-[24rpx] text-black/60 text-center">上传视频</div>
  284. </div>
  285. </div>
  286. <dragImg keyName='url' v-if="imgList.length > 0" v-model="imgList" @del="delImg" @sortChange="sortChange" :number="String(circleType) === '2' ? 30 : 9"></dragImg>
  287. <SectionHeading
  288. title="标签"
  289. custom-class="my-6"
  290. :path="`/pages-sub/publish/tags/index?tagName=${tagName}`"
  291. size="base"
  292. >
  293. <template #start>
  294. <div class="flex gap-2.5 overflow-x-scroll">
  295. <template v-if="tagName !== ''">
  296. <template v-for="it of tagName.split(',')" :key="it">
  297. <div
  298. class="h-6 px-2 py-0.5 bg-[#f3f3f3] rounded-[3px] justify-center items-center gap-2 inline-flex shrink-0"
  299. >
  300. <div
  301. class="text-center text-black/90 text-xs font-normal font-['PingFang_SC'] leading-tight"
  302. >
  303. #{{ it }}
  304. </div>
  305. </div>
  306. </template>
  307. </template>
  308. </div>
  309. </template>
  310. </SectionHeading>
  311. <div class="flex-1"></div>
  312. <div class="w-full relative z-9">
  313. <BottomAppBar fixed safe-area-inset-bottom placeholder>
  314. <div class="w-full">
  315. <wd-button type="primary" :round="false" block :loading="publishing" @click="handleSubmit">
  316. 发布
  317. </wd-button>
  318. </div>
  319. </BottomAppBar>
  320. </div>
  321. </div>
  322. </template>
  323. <style>
  324. .display{
  325. display: none !important;
  326. }
  327. </style>