create-circle.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. <template>
  2. <view class="create-circle-page">
  3. <view class="nav-bar">
  4. <view class="nav-back" @tap="goBack"><text class="nav-back-icon">‹</text></view>
  5. <text class="nav-title">创建圈子</text>
  6. <view class="nav-placeholder"></view>
  7. </view>
  8. <scroll-view class="content" scroll-y>
  9. <view class="form-card">
  10. <view class="form-item">
  11. <text class="form-label">圈子名称 <text class="required">*</text></text>
  12. <input class="form-input" placeholder="给圈子起个名字" v-model="form.name" maxlength="30" />
  13. </view>
  14. <view class="form-item">
  15. <text class="form-label">圈子类型</text>
  16. <view class="type-grid">
  17. <view class="type-opt" :class="{ 'type-active': form.type === t.value }" v-for="t in circleTypes" :key="t.value" @tap="form.type = t.value">
  18. <text class="to-icon">{{ t.icon }}</text>
  19. <text class="to-label">{{ t.label }}</text>
  20. </view>
  21. </view>
  22. </view>
  23. <view class="form-item">
  24. <text class="form-label">圈子描述</text>
  25. <textarea class="form-textarea" placeholder="简单介绍一下这个圈子..." v-model="form.description" maxlength="200" />
  26. </view>
  27. <view class="form-item">
  28. <text class="form-label">加入方式</text>
  29. <view class="join-options">
  30. <view class="join-opt" :class="{ 'join-active': form.joinCondition === 0 }" @tap="form.joinCondition = 0">
  31. <text class="jo-icon">🌐</text>
  32. <text class="jo-label">公开加入</text>
  33. <text class="jo-desc">任何人都可以加入</text>
  34. </view>
  35. <view class="join-opt" :class="{ 'join-active': form.joinCondition === 1 }" @tap="form.joinCondition = 1">
  36. <text class="jo-icon">🔒</text>
  37. <text class="jo-label">需审核</text>
  38. <text class="jo-desc">管理员审核后加入</text>
  39. </view>
  40. <view class="join-opt" :class="{ 'join-active': form.joinCondition === 2 }" @tap="form.joinCondition = 2">
  41. <text class="jo-icon">🔗</text>
  42. <text class="jo-label">邀请制</text>
  43. <text class="jo-desc">仅邀请可加入</text>
  44. </view>
  45. </view>
  46. </view>
  47. <view class="form-item">
  48. <view class="switch-row">
  49. <text class="form-label">公开可见</text>
  50. <switch :checked="form.isPublic === 1" :color="bodyColor" @change="form.isPublic = $event.detail.value ? 1 : 0" />
  51. </view>
  52. <text class="switch-desc">其他用户可以在发现页看到此圈子</text>
  53. </view>
  54. </view>
  55. <view class="bottom-space"></view>
  56. </scroll-view>
  57. <view class="fixed-bottom">
  58. <button class="btn-create" :disabled="!form.name.trim()" @tap="handleCreate">创建圈子</button>
  59. </view>
  60. </view>
  61. </template>
  62. <script>
  63. import { BrandColors } from '@/utils/brand-colors.js'
  64. import { createGeneralCircle } from '@/utils/api.js'
  65. export default {
  66. data: function() {
  67. return {
  68. bodyColor: BrandColors.body,
  69. form: {
  70. name: '',
  71. type: 'topic',
  72. description: '',
  73. joinCondition: 0,
  74. isPublic: 1
  75. },
  76. circleTypes: [
  77. { value: 'topic', label: '话题', icon: '💬' },
  78. { value: 'activity', label: '活动', icon: '🎯' },
  79. { value: 'hobby', label: '爱好', icon: '🎨' },
  80. { value: 'health', label: '健康', icon: '💪' },
  81. { value: 'ability', label: '能力', icon: '🧠' },
  82. { value: 'product', label: '商品', icon: '🛒' }
  83. ]
  84. }
  85. },
  86. methods: {
  87. goBack: function() {
  88. uni.navigateBack()
  89. },
  90. handleCreate: function() {
  91. var self = this
  92. if (!self.form.name.trim()) return
  93. var memberId = uni.getStorageSync('currentChildId') || ''
  94. if (!memberId) {
  95. uni.showToast({ title: '请先登录', icon: 'none' })
  96. return
  97. }
  98. uni.showLoading({ title: '创建中...' })
  99. createGeneralCircle({
  100. name: self.form.name.trim(),
  101. type: self.form.type,
  102. description: self.form.description,
  103. joinCondition: self.form.joinCondition,
  104. isPublic: self.form.isPublic,
  105. creatorId: memberId,
  106. creatorType: 'child'
  107. }).then(function(res) {
  108. uni.hideLoading()
  109. if (res.code === 200 && res.data) {
  110. uni.showToast({ title: '创建成功', icon: 'success' })
  111. setTimeout(function() {
  112. uni.redirectTo({ url: '/pages/discover/circle-feed?circleId=' + res.data.id + '&name=' + encodeURIComponent(self.form.name) + '&memberCount=1' })
  113. }, 1000)
  114. } else {
  115. uni.showToast({ title: res.message || '创建失败', icon: 'none' })
  116. }
  117. }).catch(function() {
  118. uni.hideLoading()
  119. uni.showToast({ title: '创建失败,请重试', icon: 'none' })
  120. })
  121. }
  122. }
  123. }
  124. </script>
  125. <style scoped lang="scss">
  126. .create-circle-page { min-height: 100vh; background: $app-bg; padding-bottom: 160rpx; }
  127. .nav-bar {
  128. display: flex; align-items: center; justify-content: space-between;
  129. height: 88rpx; padding-top: env(safe-area-inset-top);
  130. background: $app-surface; position: sticky; top: 0; z-index: 100;
  131. border-bottom: 1rpx solid $facade-fill;
  132. }
  133. .nav-back { width: 80rpx; padding-left: 24rpx; }
  134. .nav-back-icon { font-size: 48rpx; color: $facade-text-strong; }
  135. .nav-title { font-size: 32rpx; font-weight: 600; color: $facade-text-strong; }
  136. .nav-placeholder { width: 80rpx; }
  137. .content { padding: 24rpx 32rpx; }
  138. .form-card { background: $app-surface; border-radius: 20rpx; padding: 24rpx; }
  139. .form-item { padding: 24rpx 0; border-bottom: 1rpx solid $facade-fill-2; }
  140. .form-item:last-child { border-bottom: none; }
  141. .form-label { font-size: 28rpx; font-weight: 600; color: $facade-text-strong; display: block; margin-bottom: 16rpx; }
  142. .required { color: $mat-red; }
  143. .form-input {
  144. width: 100%; height: 72rpx; background: $facade-fill-2; border-radius: 12rpx;
  145. padding: 0 20rpx; font-size: 28rpx; box-sizing: border-box;
  146. }
  147. .form-textarea {
  148. width: 100%; height: 160rpx; background: $facade-fill-2; border-radius: 12rpx;
  149. padding: 16rpx 20rpx; font-size: 26rpx; line-height: 1.6; box-sizing: border-box;
  150. }
  151. .type-grid { display: flex; flex-wrap: wrap; }
  152. .type-opt {
  153. display: flex; flex-direction: column; align-items: center;
  154. padding: 20rpx 28rpx; margin-right: 16rpx; margin-bottom: 16rpx;
  155. background: $facade-fill-2; border-radius: 16rpx; border: 2rpx solid transparent;
  156. }
  157. .type-active { border-color: $dim-body; background: $warm-peach; }
  158. .to-icon { font-size: 40rpx; margin-bottom: 8rpx; }
  159. .to-label { font-size: 24rpx; color: $facade-text-body; }
  160. .join-options { display: flex; flex-direction: column; }
  161. .join-opt {
  162. display: flex; align-items: center; padding: 20rpx;
  163. background: $facade-fill-ghost; border-radius: 12rpx; border: 2rpx solid transparent;
  164. }
  165. .join-active { border-color: $dim-body; background: $dim-body-tint; }
  166. .jo-icon { font-size: 36rpx; margin-right: 16rpx; }
  167. .jo-label { font-size: 26rpx; font-weight: 600; color: $facade-text-strong; margin-right: 16rpx; }
  168. .jo-desc { font-size: 22rpx; color: $facade-text-muted; }
  169. .switch-row { display: flex; align-items: center; justify-content: space-between; }
  170. .switch-desc { font-size: 22rpx; color: $facade-text-muted; margin-top: 8rpx; display: block; }
  171. .fixed-bottom {
  172. position: fixed; bottom: 0; left: 0; right: 0;
  173. padding: 20rpx 32rpx; padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
  174. background: $app-surface; border-top: 1rpx solid $facade-fill;
  175. }
  176. .btn-create {
  177. background: linear-gradient(135deg, $dim-body, $dim-body-light);
  178. color: $app-surface; border: none; border-radius: 40rpx;
  179. font-size: 30rpx; font-weight: 600; padding: 24rpx 0;
  180. }
  181. .btn-create[disabled] { opacity: 0.4; }
  182. .bottom-space { height: 40rpx; }
  183. </style>