selectCustomer.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. <template>
  2. <view class="container">
  3. <Step :step="currentStep" :stepsData="currentText" />
  4. <scroll-view class="content" scroll-y>
  5. <!-- 搜索栏 -->
  6. <view class="search-section">
  7. <view class="search-input-wrapper">
  8. <image class="search-icon" src="/static/image/icon_search.png"></image>
  9. <input class="search-input" type="text" placeholder="输入客户名称" v-model="searchKeyword"
  10. @input="handleSearch" />
  11. <image class="clear-icon" src="/static/image/icon_clear.png" v-if="searchKeyword"
  12. @click="clearSearch"></image>
  13. </view>
  14. <view class="section-title">已选择 {{ selectedCustomers.length }} 人:</view>
  15. <view class="selected-tags">
  16. <view class="selected-tag" v-for="(customer, index) in selectedCustomers" :key="customer.id">
  17. <text class="tag-name">{{ customer.name }}</text>
  18. <text class="tag-remove" @click="removeCustomer(customer.id)">×</text>
  19. </view>
  20. </view>
  21. </view>
  22. <!-- 已选择客户 -->
  23. <view class="selected-section">
  24. </view>
  25. <!-- 客户列表 -->
  26. <view class="customer-list">
  27. <view class="customer-item" :class="{ active: isSelected(customer.id) }"
  28. v-for="(customer, index) in filteredCustomers" :key="customer.id" @click="toggleCustomer(customer)">
  29. <view class="left">
  30. <image class="head" src="/static/image/img_avatar_client.png"></image>
  31. <view class="customer-info">
  32. <view class="customer-header">
  33. <view class="customer-name">{{ customer.name }}</view>
  34. <view class="customer-level">{{ customer.level }}</view>
  35. </view>
  36. <view class="customer-details">
  37. <view class="customer-hospital">{{ customer.hospital }}</view>
  38. <view class="customer-department">{{ customer.department }}</view>
  39. </view>
  40. </view>
  41. </view>
  42. <checkbox :value="customer.id" :checked="isSelected(customer.id)" @click.stop="toggleCustomer(customer)"
  43. color="#388BFF" />
  44. </view>
  45. </view>
  46. </scroll-view>
  47. <!-- 底部操作栏 -->
  48. <view class="bottom-bar">
  49. <view class="del-box" @click="deleteSelected">
  50. <image class="w40 h40" src="/static/image/icon_delete.png"></image>
  51. <text>删除</text>
  52. </view>
  53. <view class="action-buttons">
  54. <view class="btn btn-cancel" @click="handlePrev">上一步</view>
  55. <view class="btn btn-submit" @click="handleNext">下一步</view>
  56. </view>
  57. </view>
  58. </view>
  59. </template>
  60. <script>
  61. import Step from '@/pages_task/components/step.vue'
  62. export default {
  63. components: {
  64. Step
  65. },
  66. data() {
  67. return {
  68. currentText: [{
  69. id: 1,
  70. stepNumber: 1,
  71. title: '填写任务'
  72. },
  73. {
  74. id: 2,
  75. stepNumber: 2,
  76. title: '选择客户'
  77. },
  78. {
  79. id: 3,
  80. stepNumber: 3,
  81. title: '积分设置'
  82. }
  83. ],
  84. currentStep: 2,
  85. searchKeyword: '',
  86. selectedCustomers: [{
  87. id: 1,
  88. name: '王小明',
  89. level: '一级',
  90. hospital: '湖南省人民医院',
  91. department: '口腔科'
  92. },
  93. {
  94. id: 2,
  95. name: '李洋',
  96. level: '一级',
  97. hospital: '湖南省人民医院',
  98. department: '口腔科'
  99. }
  100. ],
  101. customerList: [{
  102. id: 1,
  103. name: '王小明',
  104. level: '一级',
  105. hospital: '湖南省人民医院',
  106. department: '口腔科'
  107. },
  108. {
  109. id: 2,
  110. name: '李洋',
  111. level: '一级',
  112. hospital: '湖南省人民医院',
  113. department: '口腔科'
  114. },
  115. {
  116. id: 3,
  117. name: '王小明',
  118. level: '一级',
  119. hospital: '湖南省人民医院',
  120. department: '口腔科'
  121. },
  122. {
  123. id: 4,
  124. name: '王小明',
  125. level: '一级',
  126. hospital: '湖南省人民医院',
  127. department: '口腔科'
  128. },
  129. {
  130. id: 5,
  131. name: '王小明',
  132. level: '一级',
  133. hospital: '湖南省人民医院',
  134. department: '口腔科'
  135. },
  136. {
  137. id: 6,
  138. name: '王小明',
  139. level: '一级',
  140. hospital: '湖南省人民医院',
  141. department: '口腔科'
  142. }
  143. ]
  144. }
  145. },
  146. computed: {
  147. filteredCustomers() {
  148. if (!this.searchKeyword.trim()) {
  149. return this.customerList
  150. }
  151. const keyword = this.searchKeyword.toLowerCase()
  152. return this.customerList.filter(customer =>
  153. customer.name.toLowerCase().includes(keyword) ||
  154. customer.hospital.toLowerCase().includes(keyword) ||
  155. customer.department.toLowerCase().includes(keyword)
  156. )
  157. }
  158. },
  159. methods: {
  160. handleSearch() {
  161. // 搜索逻辑已经在computed中处理
  162. },
  163. clearSearch() {
  164. this.searchKeyword = ''
  165. },
  166. isSelected(customerId) {
  167. return this.selectedCustomers.some(customer => customer.id === customerId)
  168. },
  169. toggleCustomer(customer) {
  170. const index = this.selectedCustomers.findIndex(item => item.id === customer.id)
  171. if (index > -1) {
  172. // 已选中,移除
  173. this.selectedCustomers.splice(index, 1)
  174. } else {
  175. // 未选中,添加
  176. this.selectedCustomers.push(customer)
  177. }
  178. },
  179. removeCustomer(customerId) {
  180. const index = this.selectedCustomers.findIndex(item => item.id === customerId)
  181. if (index > -1) {
  182. this.selectedCustomers.splice(index, 1)
  183. }
  184. },
  185. deleteSelected() {
  186. if (this.selectedCustomers.length === 0) {
  187. uni.showToast({
  188. icon: 'none',
  189. title: '请先选择要删除的客户'
  190. })
  191. return
  192. }
  193. // 这里可以添加删除逻辑,比如从列表中移除已选中的客户
  194. uni.showModal({
  195. title: '提示',
  196. content: `确定要删除选中的 ${this.selectedCustomers.length} 个客户吗?`,
  197. success: (res) => {
  198. if (res.confirm) {
  199. // 从客户列表中移除已选中的客户
  200. const selectedIds = this.selectedCustomers.map(item => item.id)
  201. this.customerList = this.customerList.filter(
  202. customer => !selectedIds.includes(customer.id)
  203. )
  204. // 清空已选中的客户
  205. this.selectedCustomers = []
  206. uni.showToast({
  207. title: '删除成功'
  208. })
  209. }
  210. }
  211. })
  212. },
  213. handlePrev() {
  214. uni.navigateBack()
  215. },
  216. handleNext() {
  217. if (this.selectedCustomers.length === 0) {
  218. uni.showToast({
  219. icon: 'none',
  220. title: '请至少选择一个客户'
  221. })
  222. return
  223. }
  224. // 跳转到下一步(积分设置)
  225. uni.navigateTo({
  226. url: '/pages_task/pointsSettings'
  227. })
  228. }
  229. }
  230. }
  231. </script>
  232. <style lang="scss" scoped>
  233. .container {
  234. min-height: 100vh;
  235. background: #F7F8FA;
  236. display: flex;
  237. flex-direction: column;
  238. &::before {
  239. content: '';
  240. position: absolute;
  241. top: 0;
  242. left: 0;
  243. right: 0;
  244. width: 100%;
  245. height: 544rpx;
  246. background: linear-gradient(180deg, #E4EFFE 0%, rgba(228, 239, 254, 0) 100%);
  247. }
  248. }
  249. .step-container {
  250. display: flex;
  251. align-items: center;
  252. justify-content: center;
  253. background: #fff;
  254. padding: 32rpx 0;
  255. margin-bottom: 20rpx;
  256. .step-item {
  257. display: flex;
  258. flex-direction: column;
  259. align-items: center;
  260. position: relative;
  261. .step-number {
  262. width: 48rpx;
  263. height: 48rpx;
  264. border-radius: 50%;
  265. background: #F2F3F5;
  266. color: #C8C9CC;
  267. display: flex;
  268. align-items: center;
  269. justify-content: center;
  270. font-size: 28rpx;
  271. font-weight: 500;
  272. margin-bottom: 8rpx;
  273. transition: all 0.3s;
  274. &.active {
  275. background: #388BFF;
  276. color: #fff;
  277. }
  278. }
  279. .step-text {
  280. font-size: 28rpx;
  281. color: #C8C9CC;
  282. transition: all 0.3s;
  283. &.active {
  284. color: #388BFF;
  285. font-weight: 500;
  286. }
  287. }
  288. &.active {
  289. .step-number {
  290. background: #388BFF;
  291. color: #fff;
  292. }
  293. .step-text {
  294. color: #388BFF;
  295. font-weight: 500;
  296. }
  297. }
  298. }
  299. .step-divider {
  300. width: 80rpx;
  301. height: 2rpx;
  302. background: #EBEDF0;
  303. margin: 0 20rpx;
  304. }
  305. }
  306. .content {
  307. flex: 1;
  308. padding: 24rpx;
  309. box-sizing: border-box;
  310. padding-bottom: 200rpx;
  311. }
  312. .search-section {
  313. background-color: #ffffff;
  314. border-radius: 24rpx 24rpx 24rpx 24rpx;
  315. padding: 24rpx;
  316. margin-bottom: 24rpx;
  317. .section-title {
  318. font-size: 24rpx;
  319. color: #999999;
  320. margin-bottom: 24rpx;
  321. }
  322. .selected-tags {
  323. display: flex;
  324. flex-wrap: wrap;
  325. gap: 16rpx;
  326. .selected-tag {
  327. display: flex;
  328. align-items: center;
  329. border-radius: 76rpx 76rpx 76rpx 76rpx;
  330. border: 2rpx solid #F5F5F5;
  331. padding: 12rpx 24rpx;
  332. font-size: 28rpx;
  333. .tag-name {
  334. color: #333;
  335. margin-right: 8rpx;
  336. }
  337. .tag-remove {
  338. color: #C8C9CC;
  339. font-size: 36rpx;
  340. line-height: 1;
  341. cursor: pointer;
  342. }
  343. }
  344. }
  345. .search-input-wrapper {
  346. background: #F7F8FA;
  347. border-radius: 38rpx 38rpx 38rpx 38rpx;
  348. position: relative;
  349. display: flex;
  350. align-items: center;
  351. padding: 0 28rpx;
  352. height: 72rpx;
  353. margin-bottom: 24rpx;
  354. .search-icon {
  355. width: 36rpx;
  356. height: 36rpx;
  357. margin-right: 16rpx;
  358. }
  359. .search-input {
  360. flex: 1;
  361. height: 100%;
  362. font-size: 28rpx;
  363. color: #333;
  364. }
  365. .clear-icon {
  366. width: 32rpx;
  367. height: 32rpx;
  368. margin-left: 16rpx;
  369. }
  370. }
  371. }
  372. .customer-list {
  373. .customer-item {
  374. border-radius: 24rpx 24rpx 24rpx 24rpx;
  375. display: flex;
  376. align-items: center;
  377. justify-content: space-between;
  378. padding: 32rpx;
  379. margin-bottom: 12rpx;
  380. background-color: #ffffff;
  381. cursor: pointer;
  382. transition: all 0.3s;
  383. &.active {
  384. background: rgba(56,139,255,0.06);
  385. }
  386. &:last-child {
  387. margin-bottom: 0;
  388. }
  389. .left {
  390. display: flex;
  391. align-items: center;
  392. .head {
  393. width: 88rpx;
  394. height: 88rpx;
  395. border-radius: 50%;
  396. margin-right: 24rpx;
  397. }
  398. .customer-info {
  399. flex: 1;
  400. .customer-header {
  401. display: flex;
  402. align-items: center;
  403. margin-bottom: 12rpx;
  404. .customer-name {
  405. font-weight: 500;
  406. font-size: 32rpx;
  407. color: #333333;
  408. margin-right: 16rpx;
  409. }
  410. .customer-level {
  411. font-size: 24rpx;
  412. color: #C89743;
  413. background: #FFF6E5;
  414. border-radius: 8rpx;
  415. padding: 4rpx 12rpx;
  416. }
  417. }
  418. .customer-details {
  419. display: flex;
  420. align-items: center;
  421. .customer-hospital {
  422. font-size: 28rpx;
  423. color: #666;
  424. margin-right: 24rpx;
  425. border-right: 2rpx solid #EAEBEE;
  426. padding-right: 24rpx;
  427. }
  428. .customer-department {
  429. font-size: 28rpx;
  430. color: #666;
  431. }
  432. }
  433. }
  434. }
  435. }
  436. }
  437. .bottom-bar {
  438. position: fixed;
  439. bottom: 0;
  440. left: 0;
  441. right: 0;
  442. background: #fff;
  443. padding: 24rpx 32rpx;
  444. border-top: 1rpx solid #F2F3F5;
  445. z-index: 100;
  446. display: flex;
  447. align-items: center;
  448. .del-box {
  449. display: flex;
  450. flex-direction: column;
  451. align-items: center;
  452. font-size: 24rpx;
  453. color: #666666;
  454. margin-right: 32rpx;
  455. cursor: pointer;
  456. }
  457. .action-buttons {
  458. display: flex;
  459. flex: 1;
  460. justify-content: space-between;
  461. .btn {
  462. width: 292rpx;
  463. height: 88rpx;
  464. display: flex;
  465. align-items: center;
  466. justify-content: center;
  467. font-size: 32rpx;
  468. font-weight: 500;
  469. border-radius: 200rpx 200rpx 200rpx 200rpx;
  470. cursor: pointer;
  471. &.btn-cancel {
  472. background: #fff;
  473. border: 2rpx solid #388BFF;
  474. color: #388BFF;
  475. }
  476. &.btn-submit {
  477. background: #388BFF;
  478. color: #fff;
  479. }
  480. }
  481. }
  482. }
  483. </style>