裂变星小程序-25.03.04
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
10 KiB

11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
  1. <template>
  2. <view class="page">
  3. <navbar title="文章分享" leftClick @leftClick="$utils.navigateBack" />
  4. <view class="content">
  5. <uv-form
  6. ref="form"
  7. :model="form"
  8. :rules="getRules()"
  9. labelPosition="left"
  10. labelWidth="300rpx"
  11. :labelStyle="{
  12. color: '#1B1B1B',
  13. fontSize: '32rpx',
  14. fontWeight: 'bold',
  15. }"
  16. errorType="toast"
  17. >
  18. <view class="form-item">
  19. <uv-form-item label="用户ID" prop="userId">
  20. <view class="form-item-content">
  21. <text>{{ userId }}</text>
  22. <view style="margin-left: 20rpx;">
  23. <button class="btn-simple" plain @click="$utils.copyText(userId)">
  24. <uv-icon name="file-text" color="#05D9A2" size="28rpx"></uv-icon>
  25. </button>
  26. </view>
  27. </view>
  28. </uv-form-item>
  29. </view>
  30. <view class="form-item">
  31. <uv-form-item label="选择封面图" prop="headImage">
  32. <view class="form-item-content">
  33. <formUpload v-model="form.headImage">
  34. <template v-slot="{ value }">
  35. <view class="flex" style="min-width: 116rpx; height: 45rpx;">
  36. <image
  37. :src="value"
  38. mode="aspectFill"
  39. style="width: 68rpx; height: 68rpx;"
  40. radius="14rpx"
  41. />
  42. <uv-icon style="margin-left: 20rpx" name="arrow-right" color="#000000" size="28rpx"></uv-icon>
  43. </view>
  44. </template>
  45. </formUpload>
  46. </view>
  47. </uv-form-item>
  48. </view>
  49. <view class="form-item">
  50. <uv-form-item label="标题" labelWidth="84rpx" prop="headTitle">
  51. <view class="form-item-content">
  52. <formInput v-model="form.headTitle" placeholder="请输入你的文章标题" width="584rpx"></formInput>
  53. </view>
  54. </uv-form-item>
  55. </view>
  56. <view class="form-item">
  57. <uv-form-item label="设置转发次数(次)" prop="num">
  58. <view class="form-item-content">
  59. <formNumberBox v-model="form.num" ></formNumberBox>
  60. </view>
  61. </uv-form-item>
  62. </view>
  63. <view class="form-item">
  64. <uv-form-item label="选择二维码" prop="wxCodeImage">
  65. <view class="form-item-content">
  66. <formUpload v-model="form.wxCodeImage">
  67. <template v-slot="{ value }">
  68. <view class="flex" style="min-width: 93rpx; height: 45rpx;">
  69. <image
  70. :src="value"
  71. mode="aspectFill"
  72. style="width: 45rpx; height: 45rpx;"
  73. radius="14rpx"
  74. />
  75. <uv-icon style="margin-left: 20rpx" name="arrow-right" color="#000000" size="28rpx"></uv-icon>
  76. </view>
  77. </template>
  78. </formUpload>
  79. </view>
  80. </uv-form-item>
  81. </view>
  82. <view class="form-item">
  83. <uv-form-item label="文章内容" prop="textDetails" labelPosition="top">
  84. <view class="editor__view" style="margin-top: 32rpx;">
  85. <editor id="editor" class="editor"
  86. placeholder="请输入你的文章内容"
  87. @ready="onEditorReady"
  88. @input="onEditroInput"
  89. ></editor>
  90. <view class="flex editor-tools">
  91. <view style="flex: 1;">
  92. <button @click="insertImage" plain class="btn-simple" style="float: left; font-size: 0;">
  93. <image src="../static/record/icon-add.png" style="width: 126rpx; height: 126rpx;" ></image>
  94. </button>
  95. </view>
  96. <view style="flex: 1; text-align: right;">
  97. <text class="editor-count">{{ `${descLen}/${descLengthLimit}` }}</text>
  98. </view>
  99. </view>
  100. </view>
  101. </uv-form-item>
  102. </view>
  103. </uv-form>
  104. </view>
  105. <!-- 审核通过 -->
  106. <button v-if="status === 1" class="button-submit" open-type="share">
  107. 发布
  108. </button>
  109. <!-- 不是 审核中 已发布 -> 创建分享 审核不通过 -->
  110. <button v-else-if="![0,1].includes(status)" class="button-submit" @click="preSubmit">
  111. 提交审核
  112. </button>
  113. <autoCrop ref="autoCropRef" @change="onSubmit"></autoCrop>
  114. </view>
  115. </template>
  116. <script>
  117. import { mapState } from 'vuex'
  118. import shareLog from '@/utils/shareLog'
  119. import formInput from '../components/formInput.vue'
  120. import formNumberBox from '../components/formNumberBox.vue'
  121. import formUpload from '../components/formUpload.vue'
  122. import formTextarea from '../components/formTextarea.vue'
  123. import autoCrop from '../components/autoCrop.vue'
  124. export default {
  125. components: {
  126. formInput,
  127. formNumberBox,
  128. formUpload,
  129. formTextarea,
  130. autoCrop,
  131. },
  132. data() {
  133. return {
  134. id: null,
  135. status: null,
  136. form: {
  137. userId: null,
  138. headImage: null,
  139. headTitle: null,
  140. num: 0,
  141. wxCodeImage: null,
  142. textDetails: null,
  143. },
  144. editorCtx: null,
  145. descLen: 0,
  146. descLengthLimit: 1000,
  147. }
  148. },
  149. computed: {
  150. ...mapState(['userInfo']),
  151. userId() {
  152. return this.userInfo?.intentionCode
  153. },
  154. },
  155. onLoad(option) {
  156. const { id } = option
  157. if (!id) {
  158. return
  159. }
  160. this.id = id
  161. this.fetchDetails(id)
  162. },
  163. onReady() {
  164. this.$refs.form.setRules(this.getRules());
  165. },
  166. onShareAppMessage(res) {
  167. const {
  168. headTitle,
  169. headImage,
  170. } = this.form
  171. let o = {
  172. title : headTitle,
  173. imageUrl: headImage,
  174. path: `/pages_order/sharing/article?id=${this.id}&state=3&shareId=${this.userInfo.id}`
  175. }
  176. //调用增加分享次数的方法
  177. const params = {
  178. id:this.id,
  179. state:"3",
  180. }
  181. this.$fetch('addLogShareInfo', params)
  182. shareLog.insert(this.id)
  183. this.isLocked = false
  184. return o
  185. },
  186. methods: {
  187. onEditorReady() {
  188. uni.createSelectorQuery().select('#editor').context((res) => {
  189. this.editorCtx = res.context
  190. }).exec()
  191. },
  192. onEditroInput(e) {
  193. const { text } = e.detail
  194. this.descLen = text?.length || 0
  195. },
  196. insertImage() {
  197. uni.chooseImage({
  198. count: 1,
  199. success: (res) => {
  200. // this.editorCtx.insertImage({
  201. // src: res.tempFilePaths[0],
  202. // alt: '图像',
  203. // })
  204. // todo: check
  205. this.$Oss.ossUpload(res.tempFilePaths[0]).then(url => {
  206. this.editorCtx.insertImage({
  207. src: url,
  208. alt: '图像',
  209. })
  210. })
  211. }
  212. })
  213. },
  214. setEditorContents(html) {
  215. if (!this.editorCtx) {
  216. setTimeout(() => {
  217. this.setEditorContents(html)
  218. }, 200)
  219. return
  220. }
  221. this.editorCtx.setContents({ html })
  222. },
  223. getEditorContents() {
  224. return new Promise((resolve, reject) => {
  225. this.editorCtx.getContents({
  226. success: (e) => {
  227. const { html, text } = e
  228. resolve({ html, text })
  229. },
  230. fail: () => {
  231. reject()
  232. }
  233. })
  234. })
  235. },
  236. getRules() {
  237. const textDetailsValidator = async (rule, value, callback) => {
  238. const textDetails = (await this.getEditorContents())?.html
  239. if (textDetails) {
  240. callback()
  241. return
  242. }
  243. callback(new Error('请输入文章内容'))
  244. }
  245. return {
  246. 'headImage': {
  247. type: 'string',
  248. required: true,
  249. message: '请选择封面图',
  250. },
  251. 'headTitle': {
  252. type: 'string',
  253. required: true,
  254. message: '请输入你的文章标题',
  255. },
  256. 'num': {
  257. type: 'number',
  258. required: true,
  259. message: '请设置转发次数(大于0)',
  260. validator: (rule, value, callback) => {
  261. if (value > 0) {
  262. return true
  263. }
  264. return false;
  265. },
  266. },
  267. 'wxCodeImage': {
  268. type: 'string',
  269. required: true,
  270. message: '请选择二维码',
  271. },
  272. 'textDetails': {
  273. asyncValidator: textDetailsValidator,
  274. },
  275. }
  276. },
  277. async fetchDetails(id) {
  278. try {
  279. const result = await this.$fetch('getArticleShareInfo', { id })
  280. const {
  281. userId,
  282. headImage,
  283. headTitle,
  284. num,
  285. wxCodeImage,
  286. textDetails,
  287. status,
  288. } = result || {}
  289. this.form = {
  290. userId,
  291. headImage,
  292. headTitle,
  293. num,
  294. wxCodeImage,
  295. textDetails,
  296. }
  297. this.status = status
  298. this.setEditorContents(textDetails)
  299. } catch (err) {
  300. }
  301. },
  302. async preSubmit() {
  303. try {
  304. await this.$refs.form.validate()
  305. this.$refs.autoCropRef.set(this.form.headImage)
  306. } catch (err) {
  307. }
  308. },
  309. async onSubmit(headImage) {
  310. try {
  311. await this.$refs.form.validate()
  312. const textDetails = (await this.getEditorContents())?.html
  313. const {
  314. headTitle,
  315. num,
  316. wxCodeImage,
  317. } = this.form
  318. const params = {
  319. userId: this.userId,
  320. headImage,
  321. headTitle,
  322. num,
  323. wxCodeImage,
  324. textDetails,
  325. }
  326. if (this.id) {
  327. params.id = this.id
  328. }
  329. await this.$fetch('saveOrUpdateArticleShare', params)
  330. uni.showToast({
  331. title: '提交成功',
  332. icon: 'none'
  333. })
  334. setTimeout(uni.navigateBack, 1000, -1)
  335. } catch (err) {
  336. }
  337. },
  338. }
  339. }
  340. </script>
  341. <style scoped lang="scss">
  342. @import '../styles/pageForm.scss';
  343. .editor__view {
  344. background-color: #F3F3F3;
  345. border-radius: 12rpx;
  346. }
  347. .editor {
  348. height: 253rpx;
  349. padding: 20rpx;
  350. &-tools {
  351. align-items: flex-end;
  352. padding: 0 20rpx 16rpx 14rpx;
  353. }
  354. &-count {
  355. color: #999999;
  356. font-size: 28rpx;
  357. }
  358. }
  359. </style>