create.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <template>
  2. <view class="container" :style="{ '--font-scale': fontScale }">
  3. <view class="form">
  4. <view class="form-item">
  5. <text class="label">任务模板名称</text>
  6. <input class="input" v-model="form.name" placeholder="如:21天养成学习习惯" />
  7. </view>
  8. <view class="form-item">
  9. <text class="label">详细介绍</text>
  10. <textarea class="textarea" v-model="form.description" placeholder="描述任务模板的内容和目标" />
  11. </view>
  12. <view class="form-item">
  13. <text class="label">周期天数</text>
  14. <input class="input" type="number" v-model="form.cycleDays" placeholder="如:21" />
  15. </view>
  16. <view class="form-item">
  17. <text class="label">分类</text>
  18. <picker :range="categories" @change="onCategoryChange">
  19. <view class="picker">
  20. {{ form.category || '请选择分类' }}
  21. </view>
  22. </picker>
  23. </view>
  24. <view class="form-item">
  25. <text class="label">价格 (元)</text>
  26. <input class="input" type="digit" v-model="form.price" placeholder="0 表示免费" />
  27. </view>
  28. <view class="form-item">
  29. <text class="label">封面图</text>
  30. <view class="cover-upload" @click="chooseImage">
  31. <image v-if="form.coverImage" :src="form.coverImage" mode="aspectFill" class="cover-image"></image>
  32. <text v-else class="upload-icon">+</text>
  33. </view>
  34. </view>
  35. <view class="form-item">
  36. <text class="label">是否公开</text>
  37. <switch v-model="form.isPublic" :checked="form.isPublic" @change="onPublicChange" />
  38. <text class="switch-label">{{ form.isPublic ? '公开到市场' : '仅分享链接' }}</text>
  39. </view>
  40. <button class="btn-submit" :loading="submitting" :disabled="submitting" @click="submit">保存</button>
  41. </view>
  42. </view>
  43. </template>
  44. <script>
  45. import { createPackage } from '@/utils/api.js'
  46. import { pickImage } from '@/utils/image-picker.js'
  47. import fontScaleMixin from '@/mixins/font-scale.js'
  48. export default {
  49. mixins: [fontScaleMixin],
  50. data() {
  51. return {
  52. form: {
  53. name: '',
  54. description: '',
  55. cycleDays: 21,
  56. category: '',
  57. price: 0,
  58. isPublic: false,
  59. coverImage: ''
  60. },
  61. categories: ['学习', '习惯', '健康', '情绪', '其他'],
  62. submitting: false
  63. }
  64. },
  65. methods: {
  66. onCategoryChange(e) {
  67. this.form.category = this.categories[e.detail.value]
  68. },
  69. onPublicChange(e) {
  70. this.form.isPublic = e.detail.value
  71. },
  72. chooseImage() {
  73. pickImage({
  74. count: 1,
  75. success: (res) => {
  76. this.form.coverImage = res.tempFilePaths[0]
  77. }
  78. })
  79. },
  80. async submit() {
  81. if (this.submitting) return
  82. if (!this.form.name) {
  83. uni.showToast({ title: '请输入任务模板名称', icon: 'none' })
  84. return
  85. }
  86. if (!this.form.cycleDays) {
  87. uni.showToast({ title: '请输入周期天数', icon: 'none' })
  88. return
  89. }
  90. this.submitting = true
  91. uni.showLoading({ title: '保存中...' })
  92. try {
  93. await createPackage({
  94. ...this.form,
  95. isPublic: this.form.isPublic ? 1 : 0
  96. })
  97. uni.showToast({ title: '创建成功' })
  98. setTimeout(() => {
  99. uni.navigateBack()
  100. }, 1500)
  101. } catch (e) {
  102. uni.showToast({ title: '创建失败', icon: 'none' })
  103. } finally {
  104. this.submitting = false
  105. uni.hideLoading()
  106. }
  107. }
  108. }
  109. }
  110. </script>
  111. <style scoped lang="scss">
  112. .container {
  113. min-height: 100vh;
  114. background: $facade-fill-2;
  115. padding: $uni-space-page;
  116. }
  117. .form {
  118. background: $app-surface;
  119. border-radius: 16rpx;
  120. padding: $uni-space-page;
  121. }
  122. .form-item {
  123. margin-bottom: $uni-space-lg;
  124. }
  125. .label {
  126. display: block;
  127. font-size: calc(28rpx * var(--font-scale, 1));
  128. color: $facade-text-strong;
  129. margin-bottom: 16rpx;
  130. }
  131. .input, .textarea {
  132. width: 100%;
  133. padding: 20rpx;
  134. background: $facade-fill-2;
  135. border-radius: 16rpx;
  136. font-size: calc(28rpx * var(--font-scale, 1));
  137. }
  138. .textarea {
  139. height: 160rpx;
  140. }
  141. .picker {
  142. padding: 20rpx;
  143. background: $facade-fill-2;
  144. border-radius: 16rpx;
  145. font-size: calc(28rpx * var(--font-scale, 1));
  146. color: $facade-text-strong;
  147. }
  148. .cover-upload {
  149. width: 200rpx;
  150. height: 200rpx;
  151. background: $facade-fill-2;
  152. border-radius: 16rpx;
  153. display: flex;
  154. justify-content: center;
  155. align-items: center;
  156. }
  157. .upload-icon {
  158. font-size: calc(64rpx * var(--font-scale, 1));
  159. color: $facade-text-ghost;
  160. }
  161. .cover-image {
  162. width: 200rpx;
  163. height: 200rpx;
  164. border-radius: 16rpx;
  165. }
  166. .switch-label {
  167. margin-left: 20rpx;
  168. font-size: calc(26rpx * var(--font-scale, 1));
  169. color: $facade-text-body;
  170. }
  171. .btn-submit {
  172. background: $mat-green;
  173. color: $app-surface;
  174. border-radius: 24rpx;
  175. margin-top: 40rpx;
  176. }
  177. </style>