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.

352 lines
8.5 KiB

  1. <template>
  2. <view class="personality-select-container">
  3. <!-- 性格描述 -->
  4. <view class="personality-description">
  5. <view class="section-title">性格描述</view>
  6. <view class="description-input">
  7. <textarea
  8. v-model="personalityDescription"
  9. placeholder="请描述您的宠物性格"
  10. class="description-textarea"
  11. maxlength="200"
  12. ></textarea>
  13. </view>
  14. </view>
  15. <!-- 快捷选择 -->
  16. <view class="quick-selection">
  17. <view class="section-title">快捷选择</view>
  18. <view class="selection-grid">
  19. <view
  20. v-for="(item, index) in personalityOptions"
  21. :key="index"
  22. :class="['selection-item', { 'selected': selectedPersonalities.includes(item) }]"
  23. @click="togglePersonality(item)"
  24. >
  25. {{ item }}
  26. </view>
  27. </view>
  28. </view>
  29. <!-- 保存按钮 -->
  30. <view class="save-button-container">
  31. <u-button
  32. color="#FFBF60"
  33. @click="savePersonality"
  34. :loading="loading"
  35. class="save-button"
  36. >
  37. <view style="color: #fff;">保存</view>
  38. </u-button>
  39. </view>
  40. </view>
  41. </template>
  42. <script>
  43. import { getDictList } from "@/api/system/user"
  44. export default {
  45. data() {
  46. return {
  47. loading: false,
  48. personalityDescription: '',
  49. selectedPersonalities: [],
  50. personalityOptions: [],
  51. originalPersonality: ''
  52. }
  53. },
  54. watch: {
  55. // 监听输入框内容变化,同步快捷选择状态
  56. personalityDescription: {
  57. handler(newVal) {
  58. this.syncSelectedPersonalities();
  59. },
  60. immediate: true
  61. },
  62. // 监听快捷选择选项加载完成
  63. personalityOptions: {
  64. handler() {
  65. this.syncSelectedPersonalities();
  66. },
  67. immediate: true
  68. }
  69. },
  70. onLoad(options) {
  71. // 接收传入的性格数据
  72. if (options.personality) {
  73. this.originalPersonality = decodeURIComponent(options.personality);
  74. this.parsePersonality(this.originalPersonality);
  75. }
  76. },
  77. mounted() {
  78. this.getPersonalityDataList();
  79. },
  80. methods: {
  81. // 同步快捷选择状态
  82. syncSelectedPersonalities() {
  83. if (!this.personalityDescription || this.personalityOptions.length === 0) {
  84. this.selectedPersonalities = [];
  85. return;
  86. }
  87. // 将输入框内容按逗号分割
  88. const descriptionItems = this.personalityDescription.split(',')
  89. .map(item => item.trim())
  90. .filter(item => item.length > 0);
  91. // 找出哪些是快捷选择项
  92. this.selectedPersonalities = descriptionItems.filter(item =>
  93. this.personalityOptions.includes(item)
  94. );
  95. },
  96. // 解析传入的性格数据
  97. parsePersonality(personality) {
  98. if (!personality) return;
  99. // 等待API数据加载完成后再解析
  100. if (this.personalityOptions.length === 0) {
  101. setTimeout(() => {
  102. this.parsePersonality(personality);
  103. }, 100);
  104. return;
  105. }
  106. // 处理数组形式的性格数据
  107. if (Array.isArray(personality)) {
  108. // 分离描述和快捷选择
  109. this.selectedPersonalities = personality.filter(item =>
  110. this.personalityOptions.includes(item)
  111. );
  112. // 将所有内容都显示在输入框中
  113. this.personalityDescription = personality.join(',');
  114. } else {
  115. // 兼容字符串形式的数据
  116. const parts = personality.split(',');
  117. // 识别哪些是快捷选择项
  118. this.selectedPersonalities = parts.filter(item =>
  119. this.personalityOptions.includes(item.trim())
  120. );
  121. // 将所有内容都显示在输入框中
  122. this.personalityDescription = personality;
  123. }
  124. },
  125. // 切换性格选择
  126. togglePersonality(personality) {
  127. const isSelected = this.selectedPersonalities.includes(personality);
  128. if (isSelected) {
  129. // 取消选择:从输入框中移除对应文本
  130. this.removeFromDescription(personality);
  131. } else {
  132. // 选择:添加到输入框中
  133. this.addToDescription(personality);
  134. }
  135. // selectedPersonalities会通过watch自动更新
  136. },
  137. // 添加性格到描述中
  138. addToDescription(personality) {
  139. if (this.personalityDescription.trim()) {
  140. // 如果输入框已有内容,用逗号分隔
  141. if (!this.personalityDescription.includes(personality)) {
  142. this.personalityDescription += ',' + personality;
  143. }
  144. } else {
  145. // 如果输入框为空,直接添加
  146. this.personalityDescription = personality;
  147. }
  148. },
  149. // 从描述中移除性格
  150. removeFromDescription(personality) {
  151. if (!this.personalityDescription.includes(personality)) return;
  152. // 将描述按逗号分割
  153. let parts = this.personalityDescription.split(',').map(item => item.trim());
  154. // 移除指定的性格
  155. parts = parts.filter(item => item !== personality);
  156. // 重新组合
  157. this.personalityDescription = parts.join(',');
  158. },
  159. // 获取性格数据列表
  160. getPersonalityDataList() {
  161. getDictList('pet_personality').then(res => {
  162. if (res.code == 200) {
  163. this.personalityOptions = Array.from(new Set(res.data.map(e => e.dictLabel)));
  164. } else {
  165. this.$modal.showToast('获取性格失败');
  166. }
  167. }).catch(err => {
  168. console.error('获取性格数据失败:', err);
  169. this.$modal.showToast('获取性格数据失败');
  170. });
  171. },
  172. // 保存性格选择
  173. savePersonality() {
  174. this.loading = true;
  175. // 验证是否至少有内容
  176. if (!this.personalityDescription.trim()) {
  177. this.$modal.showToast('请至少选择一项性格特征');
  178. this.loading = false;
  179. return;
  180. }
  181. // 将输入框内容按逗号分割,去重并过滤空值
  182. const personalityItems = this.personalityDescription.split(',')
  183. .map(item => item.trim())
  184. .filter(item => item.length > 0);
  185. // 去重处理
  186. const finalPersonality = Array.from(new Set(personalityItems));
  187. // 延迟一下模拟保存过程
  188. setTimeout(() => {
  189. this.loading = false;
  190. // 返回上一页并传递选择的性格数据
  191. const pages = getCurrentPages();
  192. // 安全检查:确保有足够的页面
  193. if (!pages || pages.length < 2) {
  194. console.warn('页面栈不足,无法获取上一页')
  195. uni.navigateBack();
  196. return;
  197. }
  198. const prevPage = pages[pages.length - 2];
  199. if (prevPage && prevPage.$vm) {
  200. // 更新父页面的性格数据
  201. if (prevPage.$vm.petBaseInfo) {
  202. prevPage.$vm.petBaseInfo.personality = finalPersonality;
  203. // 触发父页面的更新事件
  204. prevPage.$vm.$emit('update:petBaseInfo', prevPage.$vm.petBaseInfo);
  205. } else {
  206. console.warn('上一页没有petBaseInfo')
  207. }
  208. } else {
  209. console.warn('无法找到上一页')
  210. }
  211. // uni.showToast({
  212. // title: '保存成功',
  213. // icon: 'success',
  214. // duration: 1500
  215. // });
  216. // 返回上一页
  217. setTimeout(() => {
  218. uni.navigateBack();
  219. }, 0);
  220. }, 0);
  221. }
  222. }
  223. }
  224. </script>
  225. <style lang="scss">
  226. .personality-select-container {
  227. min-height: 100vh;
  228. background-color: #f5f5f5;
  229. padding: 20px;
  230. box-sizing: border-box;
  231. padding-bottom: 120px;
  232. }
  233. .section-title {
  234. font-size: 16px;
  235. font-weight: bold;
  236. color: #333;
  237. margin-bottom: 15px;
  238. }
  239. .personality-description {
  240. background-color: #fff;
  241. border-radius: 8px;
  242. padding: 20px;
  243. margin-bottom: 20px;
  244. .description-input {
  245. .description-textarea {
  246. width: 100%;
  247. min-height: 100px;
  248. padding: 15px;
  249. border: 1px solid #e0e0e0;
  250. border-radius: 8px;
  251. font-size: 14px;
  252. line-height: 1.5;
  253. background-color: #fafafa;
  254. box-sizing: border-box;
  255. resize: none;
  256. &::placeholder {
  257. color: #999;
  258. }
  259. }
  260. }
  261. }
  262. .quick-selection {
  263. background-color: #fff;
  264. border-radius: 8px;
  265. padding: 20px;
  266. margin-bottom: 100px;
  267. .selection-grid {
  268. display: grid;
  269. grid-template-columns: 1fr 1fr 1fr 1fr;
  270. gap: 8px;
  271. .selection-item {
  272. padding: 10px 4px;
  273. background-color: #f5f5f5;
  274. border-radius: 6px;
  275. text-align: center;
  276. font-size: 12px;
  277. color: #666;
  278. border: 1px solid transparent;
  279. transition: all 0.3s ease;
  280. line-height: 1.1;
  281. white-space: nowrap;
  282. overflow: hidden;
  283. text-overflow: ellipsis;
  284. min-height: 40px;
  285. display: flex;
  286. align-items: center;
  287. justify-content: center;
  288. &.selected {
  289. background-color: #FFBF60;
  290. color: #fff;
  291. border-color: #FFBF60;
  292. }
  293. &:active {
  294. transform: scale(0.98);
  295. }
  296. }
  297. }
  298. }
  299. .save-button-container {
  300. position: fixed;
  301. bottom: 0;
  302. left: 0;
  303. right: 0;
  304. padding: 20px;
  305. background-color: #fff;
  306. border-top: 1px solid #e0e0e0;
  307. .save-button {
  308. width: 100%;
  309. height: 50px;
  310. border-radius: 8px;
  311. }
  312. }
  313. </style>