serviceSave.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. <template>
  2. <view style="height: 100%; background: #F8F9FA;">
  3. <van-image
  4. class="huodongText2-img"
  5. height="360rpx"
  6. :src="courseInfo.cover"
  7. width="100%"
  8. style="display: flex;align-items: center;"
  9. />
  10. <view class="huodong-ccontent" >
  11. <view class="course-content">
  12. <view class="course-title fw700 fs18">{{ courseInfo.goods_name }}</view>
  13. <view class="course-price" style="position: relative;">
  14. <span style="font-size: 24rpx; color: #C29556;">¥&nbsp;</span><span class="fw700" style="font-size: 36rpx;color: #C29556;">{{courseInfo.price_selling}}</span>
  15. <view style="position: absolute;right:0rpx;font-size: 22rpx;color:#888888; display: flex;">
  16. <view style="padding-top: 7rpx;width:28rpx;height: 28rpx ">
  17. <van-image
  18. class="huodongText2-img"
  19. height="28rpx"
  20. src="/static/cart-a.png"
  21. width="28rpx"
  22. style="display: flex;"
  23. />
  24. </view>
  25. <span style="padding-left: 20rpx;padding-right: 5rpx">&nbsp;已售:&nbsp;{{courseInfo.stock_sales}}</span>
  26. </view>
  27. </view>
  28. <u-divider line-color="#E8E8E8"></u-divider>
  29. <view class="course-title fw600">
  30. 门店信息
  31. </view>
  32. <view class="course-store display-flex-between">
  33. <view class="course-store-left">
  34. <view class="display-flex ">
  35. <view class="course-store-left-img mr10">
  36. <van-image
  37. class="huodongText2-img"
  38. height="28rpx"
  39. src="/static/hd-if-b.png"
  40. width="28rpx"
  41. style="display: flex; align-items: center;justify-content: center;"
  42. />
  43. </view>
  44. <view class="course-store-left-text">
  45. {{store_position}}
  46. </view>
  47. </view>
  48. <view class="display-flex-between ">
  49. <view class="display-flex ">
  50. <view class="course-store-left-img mr10">
  51. <van-image
  52. class="huodongText2-img"
  53. height="24rpx"
  54. src="/static/huodong-a.png"
  55. width="24rpx"
  56. style="display: flex; align-items: center;justify-content: center;"
  57. />
  58. </view>
  59. <view class="course-store-left-text">
  60. {{business_hours}}
  61. </view>
  62. </view>
  63. <view class="course-store-left-right">
  64. <view class="course-store-left-right-img " @click="openLocation">
  65. <van-image
  66. class="huodongText2-img"
  67. height="56rpx"
  68. src="/static/daohang.png"
  69. width="56rpx"
  70. style="display: flex;align-items: center; justify-content: center;"
  71. />
  72. </view>
  73. <view class="course-store-left-right-img ml10" @click="makePhoneCall">
  74. <van-image
  75. class="huodongText2-img"
  76. height="56rpx"
  77. src="/static/dianhua.png"
  78. width="56rpx"
  79. style="display: flex;align-items: center; justify-content: center;"
  80. />
  81. </view>
  82. </view>
  83. </view>
  84. </view>
  85. </view>
  86. </view>
  87. </view>
  88. <view class="course-content-title">
  89. 课程介绍
  90. </view>
  91. <view id="course-content" ref="courseContent" style="width: 95%;margin: 0 auto;" v-html="courseInfo.content">
  92. </view>
  93. <view style="width: 100%;height: 165rpx" > </view>
  94. <van-toast id="van-toast"/>
  95. <view class="bottom-navigation">
  96. <view class="bottom-navigation-div">
  97. <view style="width: 40rpx;margin-right: 30rpx" @click="toJump( 1)" >
  98. <van-image
  99. height="36rpx"
  100. src="/static/hd-icon-a.png"
  101. width="36rpx"
  102. style="display: flex;align-items: center; justify-content: center;"
  103. />
  104. <span>
  105. 首页
  106. </span>
  107. </view>
  108. <view style="width: 40rpx;position:relative" open-type="contact">
  109. <van-image
  110. height="36rpx"
  111. src="/static/hd-icon-c.png"
  112. width="36rpx"
  113. style="display: flex;align-items: center; justify-content: center;"
  114. />
  115. <span>
  116. 咨询
  117. </span>
  118. <button style="position: absolute;width: 100%;height: 100%;z-index: 999;opacity: 0;top:0;"
  119. open-type="contact" ></button>
  120. </view>
  121. </view>
  122. <button class="course-button" @click="handleRegister">报名学习</button>
  123. </view>
  124. </view>
  125. </template>
  126. <script>
  127. import {getConfigData} from '@/common/api/common.js';
  128. import Toast from "../../wxcomponents/vant/dist/toast/toast";
  129. import {getGoodsDetail} from "../../common/api";
  130. export default {
  131. components: {},
  132. data() {
  133. return {
  134. page: 1,
  135. pageSize: 10,
  136. courseTypeList: [],
  137. goods_code: 0,
  138. courseInfo: {},
  139. entry_end: 0,
  140. remainingImages: [],
  141. entry_num:0,
  142. entry_max:0,
  143. entry_balance:0,
  144. is_entry:false,
  145. suitNum:1,
  146. phoneNumber: '',
  147. store_name: '',
  148. store_position: '',
  149. business_hours: '',
  150. latlng: '',
  151. };
  152. },
  153. onLoad: function (option) {
  154. this.goods_code = option.code
  155. },
  156. onShow() {
  157. this.$nextTick(() => {
  158. this.getCourseDetail()
  159. this.setImgWidth()
  160. });
  161. },
  162. created() {
  163. const configs = uni.getStorageSync("configs");
  164. if (configs) {
  165. this.store_name = configs.store_name
  166. this.phoneNumber = configs.store_phone
  167. this.store_position = configs.store_position
  168. this.business_hours = configs.business_hours
  169. this.latlng = configs.latlng
  170. }
  171. },
  172. computed: {},
  173. watch: {},
  174. methods: {
  175. getConfigDatalist() {
  176. getConfigData({dict_id: 36}).then(({data}) => {
  177. this.courseTypeList = data.reverse();
  178. });
  179. },
  180. makePhoneCall() {
  181. uni.makePhoneCall({
  182. phoneNumber: this.phoneNumber, // 需要拨打的电话号码
  183. success() {
  184. console.log('拨打成功');
  185. },
  186. fail(err) {
  187. console.error('拨打失败', err);
  188. uni.showToast({
  189. title: '拨打失败,请检查号码!',
  190. icon: 'none'
  191. });
  192. }
  193. });
  194. },
  195. openLocation() {
  196. let [Lat, Lng] = ["36.02","117.93"]
  197. if (this.latlng){
  198. [Lat, Lng] = this.latlng.split(',')
  199. }
  200. uni.openLocation({
  201. latitude: Number.parseFloat(Lat), // 实际的纬度,这里使用的是示例值
  202. longitude: Number.parseFloat(Lng), // 实际的经度,这里使用的是示例值
  203. scale: 18, // 地图缩放级别,范围通常是5~18,18是最详细的级别
  204. name: this.store_name, // 可选,位置名称,会在地图的某些视图上显示
  205. address: this.store_position // 可选,详细地址,同样会在地图的某些视图上显示
  206. });
  207. },
  208. handleRegister() {
  209. // Toast('敬请期待');
  210. let tempList = this.courseInfo.data_specs[0].list
  211. tempList = tempList.map(item => {
  212. return {
  213. group_name: item.group,
  214. spec_name: item.name
  215. }
  216. })
  217. let specText = tempList.map(item => {
  218. return `${item.group_name}::${item.spec_name}`
  219. })
  220. // 准备发送的数据结构,包含商品代码、套件数量和规格文本
  221. const sendData = {
  222. items: [{
  223. code: this.courseInfo.code, // 商品代码
  224. count: this.suitNum, // 套件数量
  225. // 将规格文本数组用“;;”连接成单个字符串
  226. spec: specText.join(';;')
  227. }]
  228. }
  229. // 调用API创建订单
  230. this.$api.createOrder(sendData).then(res => {
  231. // 成功创建订单后,显示成功提示
  232. uni.showToast({
  233. title: '订单创建成功'
  234. })
  235. // 导航到结算中心页面,并传递订单号作为查询参数
  236. uni.navigateTo({
  237. url: `/subPages/settleCenter/courseSettleCenter?orderNo=${res.data.order_no}`
  238. })
  239. })
  240. },
  241. getCourseDetail() {
  242. getGoodsDetail({goods_code: this.goods_code}).then(({data}) => {
  243. console.log(data)
  244. this.courseInfo = data.goods
  245. // 修正 courseInfo.content 中的 src 属性值
  246. if (this.courseInfo.content) {
  247. this.courseInfo.content = this.courseInfo.content.replace(/\/apihttps:/g, 'https:');
  248. // 使用正则表达式匹配和修改 img 标签的 style 属性
  249. this.courseInfo.content = this.courseInfo.content.replace(/<img([^>]*)>/gi, (match, attributes) => {
  250. // 检查是否已经存在 style 属性
  251. if (attributes.includes('style')) {
  252. // 如果存在 style 属性,添加 width: 100%;
  253. return match.replace(/style="([^"]*)"/i, (styleMatch, styleContent) => {
  254. if (!styleContent.includes('width: 100%')) {
  255. return `style="${styleContent}; width: 100%;"`;
  256. }
  257. return styleMatch;
  258. });
  259. } else {
  260. // 如果不存在 style 属性,添加 style="width: 100%;"
  261. return match.replace(/<img/i, '<img style="width: 100%;"');
  262. }
  263. });
  264. // 使用正则表达式匹配和修改 p 标签的 style 属性
  265. this.courseInfo.content = this.courseInfo.content.replace(/<p([^>]*)>/gi, (match, attributes) => {
  266. // 检查是否已经存在 style 属性
  267. if (attributes.includes('style')) {
  268. // 如果存在 style 属性,添加新的样式
  269. return match.replace(/style="([^"]*)"/i, (styleMatch, styleContent) => {
  270. const newStyles = 'font-weight: 400; font-size: 24rpx; color: #666666; line-height: 36rpx;';
  271. if (!styleContent.includes(newStyles)) {
  272. return `style="${styleContent}; ${newStyles}"`;
  273. }
  274. return styleMatch;
  275. });
  276. } else {
  277. // 如果不存在 style 属性,添加 style 属性
  278. const newStyles = 'font-weight: 400; font-size: 24rpx; color: #666666; line-height: 36rpx;';
  279. return match.replace(/<p/i, `<p style="${newStyles}"`);
  280. }
  281. });
  282. }
  283. // 确保在数据更新后调用 setImgWidth
  284. this.$nextTick(() => {
  285. this.setImgWidth();
  286. });
  287. });
  288. },
  289. setImgWidth() {
  290. this.$nextTick(() => {
  291. if (this.$refs.courseContent) {
  292. const imgElements = this.$refs.courseContent.querySelectorAll('img');
  293. imgElements.forEach(img => {
  294. img.style.width = '100%';
  295. });
  296. } else {
  297. console.log(this.$refs)
  298. }
  299. });
  300. },
  301. getStyles(index=0) {
  302. let le =28
  303. let py=30
  304. if (this.entry_num%2==1){
  305. py+= 224/2-(84/2)-(le*Math.floor(this.entry_num / 2 ))-le/2
  306. }else{
  307. py+=224/2-(84/2)-(le*this.entry_num/2)
  308. }
  309. let right= index*le+py
  310. var newVar = {
  311. position: 'absolute',
  312. width: '84rpx',
  313. height: '84rpx',
  314. borderRadius: '84rpx',
  315. top: '30rpx',
  316. right: right+'rpx',
  317. };
  318. return newVar
  319. },
  320. toJump( index) {
  321. if(index==1){
  322. uni.switchTab({
  323. url:'/pages/home/index'
  324. });
  325. }else if(index==2){
  326. }
  327. },
  328. },
  329. };
  330. </script>
  331. <style lang="scss" scoped>
  332. .common-page {
  333. height: 100%;
  334. padding: 30rpx;
  335. }
  336. .huodong-ccontent {
  337. position: relative; /* 相对定位 */
  338. width: 650rpx;
  339. padding: 0rpx;
  340. margin: 30rpx auto;
  341. margin-bottom: 0;
  342. padding: 30rpx;
  343. background: #FFFFFF;
  344. border-radius: 16rpx 16rpx 16rpx 16rpx;
  345. }
  346. .course-content {
  347. margin-top: 30 rp;
  348. .course-title {
  349. font-family: PingFang SC-粗体;
  350. font-weight: normal;
  351. color: #333333;
  352. line-height: 40rpx;
  353. text-align: left;
  354. font-style: normal;
  355. text-transform: none;
  356. margin-bottom: 16rpx;
  357. }
  358. .course-price {
  359. font-family: 苹方, 苹方;
  360. font-weight: 400;
  361. font-size: 24rpx;
  362. color: #666666;
  363. line-height: 40rpx;
  364. text-align: justify;
  365. font-style: normal;
  366. text-transform: none;
  367. display: flex;
  368. }
  369. .course-store {
  370. &-left{
  371. width: 100%;
  372. &-img{
  373. display: flex;
  374. align-items: center;
  375. justify-content: center;
  376. width: 28rpx;
  377. height: 28rpx;
  378. }
  379. &-text{
  380. font-family: PingFang SC, PingFang SC;
  381. font-weight: 500;
  382. font-size: 24rpx;
  383. color: #666666;
  384. line-height: 36rpx;
  385. text-align: left;
  386. font-style: normal;
  387. text-transform: none;
  388. }
  389. &-right{
  390. display: flex;
  391. align-items: center;
  392. justify-content: center;
  393. &-img{
  394. }
  395. }
  396. }
  397. }
  398. }
  399. .bottom-navigation{
  400. position: fixed;
  401. // 文字垂直居中
  402. display: flex;
  403. align-items: center;
  404. justify-content: center;
  405. bottom: 0;
  406. height: 100rpx;
  407. width: calc(100% - 40rpx);
  408. background: #FFFFFF;
  409. box-shadow: 0rpx -2rpx 0rpx 0rpx #F1F3F6;
  410. border-radius: 24rpx 24rpx 0rpx 0rpx;
  411. border: 0rpx solid #979797;
  412. padding: 20rpx 20rpx 68rpx 20rpx ;
  413. &-div{
  414. height: 76rpx;
  415. width: 404rpx;
  416. padding-top: 10rpx;
  417. // 文字垂直居中
  418. display: flex;
  419. align-items: center;
  420. padding-left: 30rpx;
  421. span{
  422. font-family: PingFang SC, PingFang SC;
  423. font-weight: 400;
  424. font-size: 20rpx;
  425. color: #333333;
  426. line-height: 32rpx;
  427. text-align: left;
  428. font-style: normal;
  429. text-transform: none;
  430. }
  431. }
  432. .course-button {
  433. width: 264rpx;
  434. height: 80rpx;
  435. background: linear-gradient(315deg, #CA9359 0%, #E2B98E 100%);
  436. border-radius: 292rpx 292rpx 292rpx 292rpx;
  437. font-family: PingFang SC, PingFang SC;
  438. font-weight: 400;
  439. font-size: 28rpx;
  440. color: #FFFFFF;
  441. line-height: 36rpx;
  442. text-align: center;
  443. font-style: normal;
  444. text-transform: none;
  445. // 文字垂直居中
  446. display: flex;
  447. align-items: center;
  448. justify-content: center;
  449. }
  450. }
  451. /* 设置 v-html 渲染的内容中的 img 标签宽度为 100% */
  452. [v-html] img {
  453. width: 100%!important;
  454. }
  455. /* 定义 CSS 变量 */
  456. :root {
  457. --nav-bar-icon-color: black;
  458. --nav-bar-arrow-size: 16px;
  459. --tab-font-size: 28rpx;
  460. }
  461. .course-content-title {
  462. margin: 30rpx auto;
  463. width: 680rpx;
  464. // 垂直居中
  465. font-family: PingFang SC, PingFang SC;
  466. font-weight: 400;
  467. font-size: 28rpx;
  468. color: #333333;
  469. line-height: 40rpx;
  470. font-style: normal;
  471. text-transform: none;
  472. margin-bottom: 20rpx;
  473. // 加粗
  474. font-weight: bold;
  475. }
  476. /* 确保 van-nav-bar 内部的内容能够正确适应新的高度 */
  477. /deep/ .van-nav-bar__title {
  478. font-family: PingFang SC, PingFang SC !important;
  479. font-weight: 400 !important;
  480. font-size: 36rpx !important;
  481. color: #333333 !important;
  482. text-align: center;
  483. // 加粗
  484. // font-weight: bold;
  485. }
  486. /deep/ .van-nav-bar__content {
  487. text-align: center;
  488. }
  489. #course-content img{
  490. width: 100%!important;
  491. }
  492. /* 添加 van-tab 标题的字体大小样式 */
  493. /deep/ .van-tab__text {
  494. font-family: PingFang SC, PingFang SC;
  495. font-weight: 400;
  496. font-size: 28rpx;
  497. }
  498. </style>