index.html 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
  7. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=no,minimal-ui">
  8. <title>菩提阁</title>
  9. <link rel="icon" href="images/favico.ico">
  10. <!--不同屏幕尺寸根字体设置-->
  11. <script src="js/base.js"></script>
  12. <!--element-ui的样式-->
  13. <link rel="stylesheet" href="../backend/plugins/element-ui/index.css" />
  14. <!--引入vant样式-->
  15. <link rel="stylesheet" href="styles/vant.min.css"/>
  16. <!-- 引入样式 -->
  17. <link rel="stylesheet" href="styles/index.css" />
  18. <!--本页面内容的样式-->
  19. <link rel="stylesheet" href="styles/main.css" />
  20. </head>
  21. <body>
  22. <div id="main" class="app">
  23. <div class="divHead">
  24. <img src="images/user.png" @click="toUserPage"/>
  25. </div>
  26. <div class="divTitle">
  27. <div class="divStatic">
  28. <img src="images/logo.png" class="logo"/>
  29. <div class="divDesc">
  30. <div class="divName">菩提阁餐厅</div>
  31. <div class="divSend">
  32. <span><img src="images/time.png"/> 距离1.5km</span>
  33. <span><img src="images/money.png"/> 配送费6元</span>
  34. <span><img src="images/location.png"/> 预计时长12min</span>
  35. </div>
  36. </div>
  37. </div>
  38. <div class="divDesc">
  39. 简介: 菩提阁中餐厅是菩提阁点餐的独立的品牌,定位“大众 化的美食外送餐饮”,旨为顾客打造专业美食。
  40. </div>
  41. </div>
  42. <div class="divBody">
  43. <div class="divType">
  44. <ul>
  45. <li v-for="(item,index) in categoryList" :key="index" @click="categoryClick(index,item.id,item.type)" :class="{active:activeType === index}">{{item.name}}</li>
  46. </ul>
  47. </div>
  48. <div class="divMenu">
  49. <div>
  50. <div class="divItem" v-for="(item,index) in dishList" :key="index" @click="dishDetails(item)">
  51. <el-image :src="imgPathConvert(item.image)" >
  52. <div slot="error" class="image-slot">
  53. <img src="images/noImg.png"/>
  54. </div>
  55. </el-image>
  56. <div>
  57. <div class="divName">{{item.name}}</div>
  58. <div class="divDesc">{{item.description}}</div>
  59. <div class="divDesc">{{'月销' + (item.saleNum ? item.saleNum : 0) }}</div>
  60. <div class="divBottom"><span>¥</span><span>{{item.price/100}}</span></div>
  61. <div class="divNum">
  62. <div class="divSubtract" v-if="item.number > 0">
  63. <img src="images/subtract.png" @click.prevent.stop="subtractCart(item)"/>
  64. </div>
  65. <div class="divDishNum">{{item.number}}</div>
  66. <div class="divTypes" v-if="item.flavors && item.flavors.length > 0 && !item.number " @click.prevent.stop="chooseFlavorClick(item)">选择规格</div>
  67. <div class="divAdd" v-else>
  68. <img src="images/add.png" @click.prevent.stop="addCart(item)"/>
  69. </div>
  70. </div>
  71. </div>
  72. </div>
  73. </div>
  74. </div>
  75. </div>
  76. <div class="divLayer">
  77. <div class="divLayerLeft"></div>
  78. <div class="divLayerRight"></div>
  79. </div>
  80. <div class="divCart" v-if="categoryList.length > 0">
  81. <div :class="{imgCartActive: cartData && cartData.length > 0, imgCart:!cartData || cartData.length<1}" @click="openCart"></div>
  82. <div :class="{divGoodsNum:1===1, moreGoods:cartData && cartData.length > 99}" v-if="cartData && cartData.length > 0">{{ goodsNum }}</div>
  83. <div class="divNum">
  84. <span>¥</span>
  85. <span>{{goodsPrice}}</span>
  86. </div>
  87. <div class="divPrice"></div>
  88. <div :class="{btnSubmitActive: cartData && cartData.length > 0, btnSubmit:!cartData || cartData.length<1}" @click="toAddOrderPage">去结算</div>
  89. </div>
  90. <van-dialog v-model="dialogFlavor.show" :show-confirm-button="false" class="dialogFlavor" ref="flavorDialog">
  91. <div class="dialogTitle">{{dialogFlavor.name}}</div>
  92. <div class="divContent">
  93. <div v-for="flavor in dialogFlavor.flavors" :key="flavor.id">
  94. <div class="divFlavorTitle">{{flavor.name}}</div>
  95. <span v-for="item in JSON.parse(flavor.value)"
  96. :key="item"
  97. @click="flavorClick(flavor,item)"
  98. :class="{spanActive:flavor.dishFlavor === item}"
  99. >{{item}}</span>
  100. </div>
  101. </div>
  102. <div class="divBottom">
  103. <div><span class="spanMoney">¥</span>{{dialogFlavor.price/100}}</div>
  104. <div @click="dialogFlavorAddCart">加入购物车</div>
  105. </div>
  106. <div class="divFlavorClose" @click="dialogFlavor.show = false">
  107. <img src="images/close.png"/>
  108. </div>
  109. </van-dialog>
  110. <van-popup v-model="cartDialogShow" position="bottom" :style="{ height: '50%' }" class="dialogCart">
  111. <div class="divCartTitle">
  112. <div class="title">购物车</div>
  113. <div class="clear" @click="clearCart">
  114. <i class="el-icon-delete"></i> 清空
  115. </div>
  116. </div>
  117. <div class="divCartContent">
  118. <div v-for="item in cartData" :key="item.id" class="divCartItem">
  119. <el-image :src="imgPathConvert(item.image)" >
  120. <div slot="error" class="image-slot">
  121. <img src="images/noImg.png"/>
  122. </div>
  123. </el-image>
  124. <div class="divDesc">
  125. <div class="name">{{item.name}}</div>
  126. <div class="price">
  127. <span class="spanMoney">¥</span>{{item.amount}}</div>
  128. </div>
  129. <div class="divNum">
  130. <div class="divSubtract">
  131. <img src="images/subtract.png" @click="cartNumberSubtract(item)"/>
  132. </div>
  133. <div class="divDishNum">{{item.number}}</div>
  134. <div class="divAdd">
  135. <img src="images/add.png" @click="cartNumAdd(item)"/>
  136. </div>
  137. </div>
  138. <div class="divSplit"></div>
  139. </div>
  140. </div>
  141. </van-popup>
  142. <van-dialog v-model="detailsDialog.show"
  143. :show-confirm-button="false"
  144. class="detailsDialog"
  145. ref="detailsDialog"
  146. v-if="detailsDialog.show"
  147. >
  148. <div class="divContainer">
  149. <el-image :src="imgPathConvert(detailsDialog.item.image)" >
  150. <div slot="error" class="image-slot">
  151. <img src="images/noImg.png"/>
  152. </div>
  153. </el-image>
  154. <div class="title">{{detailsDialog.item.name}}</div>
  155. <div class="content">{{detailsDialog.item.description}}</div>
  156. </div>
  157. <div class="divNum">
  158. <div class="left">
  159. <span>¥</span><span>{{detailsDialog.item.price/100}}</span>
  160. </div>
  161. <div class="right">
  162. <div class="divSubtract" v-if="detailsDialog.item.number > 0">
  163. <img src="images/subtract.png" @click="subtractCart(detailsDialog.item)"/>
  164. </div>
  165. <div class="divDishNum">{{detailsDialog.item.number}}</div>
  166. <div class="divTypes" v-if="detailsDialog.item.flavors && detailsDialog.item.flavors.length > 0 && !detailsDialog.item.number " @click ="chooseFlavorClick(detailsDialog.item)">选择规格</div>
  167. <div class="divAdd" v-else>
  168. <img src="images/add.png" @click="addCart(detailsDialog.item)"/>
  169. </div>
  170. </div>
  171. </div>
  172. <div class="detailsDialogClose" @click="detailsDialog.show = false">
  173. <img src="images/close.png"/>
  174. </div>
  175. </van-dialog>
  176. <van-dialog v-model="setMealDialog.show"
  177. :show-confirm-button="false"
  178. class="setMealDetailsDialog"
  179. ref="setMealDetailsDialogd"
  180. v-if="setMealDialog.show"
  181. >
  182. <div class="divContainer">
  183. <div class="title">{{setMealDialog.item.name}}</div>
  184. <div class="item" v-for="(item,index) in setMealDialog.item.list" :key="index">
  185. <el-image :src="imgPathConvert(item.image)">
  186. <div slot="error" class="image-slot">
  187. <img src="images/noImg.png"/>
  188. </div>
  189. </el-image>
  190. <div class="divSubTitle">{{item.name + '(' + item.copies + '份)' }}
  191. <div class="divPrice">
  192. <span>¥</span><span>{{item.price/100}}</span>
  193. </div>
  194. </div>
  195. <div class="content">{{item.description}}</div>
  196. </div>
  197. </div>
  198. <div class="divNum">
  199. <div class="left">
  200. <span>¥</span><span>{{setMealDialog.item.price/100}}</span>
  201. </div>
  202. <div class="right">
  203. <div class="divSubtract" v-if="setMealDialog.item.number > 0">
  204. <img src="images/subtract.png" @click="subtractCart(setMealDialog.item)"/>
  205. </div>
  206. <div class="divDishNum">{{setMealDialog.item.number}}</div>
  207. <div class="divAdd" v-if="setMealDialog.item.number">
  208. <img src="images/add.png" @click="addCart(setMealDialog.item)"/>
  209. </div>
  210. <div class="addCart" @click="addCart(setMealDialog.item)" v-if="!setMealDialog.item.number">加入购物车</div>
  211. </div>
  212. </div>
  213. <div class="detailsDialogClose" @click="setMealDialog.show = false">
  214. <img src="images/close.png"/>
  215. </div>
  216. </van-dialog>
  217. </div>
  218. <!-- 开发环境版本,包含了有帮助的命令行警告 -->
  219. <script src="../backend/plugins/vue/vue.js"></script>
  220. <!-- 引入组件库 -->
  221. <script src="../backend/plugins/element-ui/index.js"></script>
  222. <!-- 引入vant样式 -->
  223. <script src="js/vant.min.js"></script>
  224. <!-- 引入axios -->
  225. <script src="../backend/plugins/axios/axios.min.js"></script>
  226. <script src="js/request.js"></script>
  227. <script src="js/common.js"></script>
  228. <script src="api/main.js"></script>
  229. </body>
  230. <script>
  231. new Vue({
  232. el:'#main',
  233. data(){
  234. return {
  235. //左边菜品类别index
  236. activeType:0,
  237. categoryList:[],
  238. categoryId:undefined,
  239. dishList:[],
  240. cartData:[],
  241. dialogFlavor:{
  242. name:'',
  243. flavors:[],
  244. dishId:undefined,
  245. price:undefined,
  246. show:false,
  247. image:''
  248. },
  249. cartDialogShow:false,
  250. detailsDialog:{
  251. show:false,
  252. item:{image:''}
  253. },
  254. setMealDialog:{
  255. show:false,
  256. item:{}
  257. },
  258. }
  259. },
  260. computed:{
  261. goodsNum(){
  262. let num = 0
  263. this.cartData.forEach(item=>{
  264. num += item.number
  265. })
  266. if(num <99){
  267. return num
  268. }else{
  269. return '99+'
  270. }
  271. },
  272. goodsPrice(){
  273. let price = 0
  274. this.cartData.forEach(item=>{
  275. price += (item.number * item.amount)
  276. })
  277. return price
  278. }
  279. },
  280. created(){
  281. },
  282. watch:{
  283. 'dialogFlavor.show'(flag){
  284. if(flag){
  285. document.querySelector('.divCart').style.zIndex = 1
  286. }else{
  287. document.querySelector('.divCart').style.zIndex = 3000
  288. }
  289. },
  290. },
  291. mounted(){
  292. this.initData()
  293. },
  294. methods:{
  295. //初始化数据
  296. initData(){
  297. Promise.all([categoryListApi(),cartListApi({})]).then(res=>{
  298. //获取分类数据
  299. if(res[0].code === 1){
  300. this.categoryList = res[0].data
  301. if(Array.isArray(res[0].data) && res[0].data.length > 0){
  302. this.categoryId = res[0].data[0].id
  303. if(res[0].data[0].type === 1){
  304. this.getDishList()
  305. }else{
  306. this.getSetmealData()
  307. }
  308. }
  309. }else{
  310. this.$notify({ type:'warning', message:res[0].msg});
  311. }
  312. //获取菜品数据
  313. if(res[1].code === 1){
  314. this.cartData = res[1].data
  315. }else{
  316. this.$notify({ type:'warning', message:res[1].msg});
  317. }
  318. })
  319. },
  320. //分类点击
  321. categoryClick(index,id,type){
  322. this.activeType = index
  323. this.categoryId = id
  324. if(type === 1){//菜品
  325. this.getDishList()
  326. }else{
  327. this.getSetmealData()
  328. }
  329. },
  330. //获取菜品数据
  331. async getDishList(){
  332. if(!this.categoryId){
  333. return
  334. }
  335. const res = await dishListApi({categoryId:this.categoryId,status:1})
  336. if(res.code === 1){
  337. let dishList = res.data
  338. const cartData = this.cartData
  339. if(dishList.length > 0 && cartData.length > 0){
  340. dishList.forEach(dish=>{
  341. cartData.forEach(cart=>{
  342. if(dish.id === cart.dishId){
  343. dish.number = cart.number
  344. }
  345. })
  346. })
  347. }
  348. this.dishList = dishList
  349. }else{
  350. this.$notify({ type:'warning', message:res.msg});
  351. }
  352. },
  353. //获取套餐数据setmealId
  354. async getSetmealData(){
  355. if(!this.categoryId){
  356. return
  357. }
  358. const res = await setmealListApi({categoryId:this.categoryId,status:1})
  359. if(res.code === 1){
  360. let dishList = res.data
  361. const cartData = this.cartData
  362. if(dishList.length > 0 && cartData.length > 0){
  363. dishList.forEach(dish=>{
  364. cartData.forEach(cart=>{
  365. if(dish.id === cart.setmealId){
  366. dish.number = cart.number
  367. }
  368. })
  369. })
  370. }
  371. this.dishList = dishList
  372. }else{
  373. this.$notify({ type:'warning', message:res.msg});
  374. }
  375. },
  376. //获取购物车数据
  377. async getCartData(){
  378. const res = await cartListApi({})
  379. if(res.code === 1){
  380. this.cartData = res.data
  381. }else{
  382. this.$notify({ type:'warning', message:res.msg});
  383. }
  384. },
  385. //菜单中往购物车中添加商品
  386. async addCart(item){
  387. let params = {
  388. amount:item.price/100,//金额
  389. dishFlavor:item.dishFlavor,//口味 如果没有传undefined
  390. dishId:undefined,//菜品id
  391. setmealId:undefined,//套餐id
  392. name:item.name,
  393. image:item.image
  394. }
  395. if(Array.isArray(item.flavors)){//表示是菜品
  396. params.dishId = item.id
  397. }else{//表示套餐 套餐没有口味
  398. params.setmealId = item.id
  399. }
  400. const res = await addCartApi(params)
  401. if(res.code === 1){
  402. this.dishList.forEach(dish=>{
  403. if(dish.id === item.id){
  404. dish.number = res.data.number
  405. }
  406. })
  407. if(this.setMealDialog.show){
  408. item.number = res.data.number
  409. }
  410. this.getCartData()
  411. }else{
  412. this.$notify({ type:'warning', message:res.msg});
  413. }
  414. },
  415. //菜单中减少选中的商品
  416. async subtractCart(item){
  417. let params = {
  418. dishId:item.id,
  419. }
  420. if(!Array.isArray(item.flavors)){
  421. params = {
  422. setmealId:item.id,
  423. }
  424. }
  425. const res = await updateCartApi(params)
  426. if(res.code === 1){
  427. this.dishList.forEach(dish=>{
  428. if(dish.id === item.id){
  429. dish.number = (res.data.number === 0 ? undefined : res.data.number)
  430. }
  431. })
  432. if(this.setMealDialog.show){
  433. item.number = (res.data.number === 0 ? undefined : res.data.number)
  434. }
  435. this.getCartData()
  436. }else{
  437. this.$notify({ type:'warning', message:res.msg});
  438. }
  439. },
  440. //展开购物车
  441. openCart(){
  442. if(this.cartData.length > 0){
  443. this.cartDialogShow = true
  444. }
  445. },
  446. //购物车中增加商品数量
  447. async cartNumAdd(item){
  448. let params = {
  449. amount:item.amount,//金额
  450. dishFlavor:item.dishFlavor,//口味 如果没有传undefined
  451. dishId:item.dishId,//菜品id
  452. setmealId:item.setmealId,//套餐id
  453. name:item.name,
  454. image:item.image
  455. }
  456. const res = await addCartApi(params)
  457. if(res.code === 1){
  458. this.dishList.forEach(dish=>{
  459. if(dish.id === (item.dishId || item.setmealId)){
  460. dish.number = res.data.number
  461. }
  462. })
  463. console.log(this.dishList)
  464. this.getCartData()
  465. }else{
  466. this.$notify({ type:'warning', message:res.msg});
  467. }
  468. },
  469. //购物车中减少商品数量
  470. async cartNumberSubtract(item){
  471. let params = {
  472. dishId:item.dishId,
  473. setmealId:item.setmealId,
  474. }
  475. const res = await updateCartApi(params)
  476. if(res.code === 1){
  477. this.dishList.forEach(dish=>{
  478. if(dish.id === (item.dishId || item.setmealId)){
  479. dish.number = (res.data.number === 0 ? undefined : res.data.number)
  480. }
  481. })
  482. this.getCartData()
  483. }else{
  484. this.$notify({ type:'warning', message:res.msg});
  485. }
  486. },
  487. //修改商品列表中的数据number
  488. changeDishList(item){
  489. for(let ele of this.dishList){
  490. if(ele.id === (item.setmealId || item.dishId)){
  491. ele.number = item.number
  492. }
  493. }
  494. },
  495. //清空购物车
  496. async clearCart(){
  497. const res = await clearCartApi()
  498. if(res.code === 1){
  499. for(let ele of this.dishList){
  500. ele.number = undefined
  501. }
  502. this.cartData = []
  503. this.cartDialogShow = false
  504. }else{
  505. this.$notify({ type:'warning', message:res.msg});
  506. }
  507. },
  508. //点击选择规格
  509. chooseFlavorClick(item){
  510. this.dialogFlavor = {
  511. name:'',
  512. flavors:[],
  513. dishId:undefined,
  514. price:undefined,
  515. show:false
  516. }
  517. this.dialogFlavor={
  518. name:item.name,
  519. flavors:item.flavors,
  520. dishId:item.id,
  521. price:item.price,
  522. show:true,
  523. image:item.image
  524. }
  525. },
  526. flavorClick(flavor,item){
  527. flavor.dishFlavor = item
  528. //强制刷新dialog的dom
  529. this.dialogFlavor.show = false
  530. this.dialogFlavor.show = true
  531. },
  532. //选择规格加入购物车
  533. dialogFlavorAddCart(){
  534. const dialogFlavor = this.dialogFlavor
  535. let flag = true
  536. let dishFlavor = []
  537. dialogFlavor.flavors.forEach(item=>{
  538. if(item.dishFlavor){
  539. dishFlavor.push(item.dishFlavor)
  540. }else{
  541. flag = false
  542. Notify({ type: 'warning', message: '请选择'+ item.name });
  543. }
  544. })
  545. if(flag){
  546. this.addCart({
  547. price:dialogFlavor.price,
  548. dishFlavor:dishFlavor.join(","),
  549. id:dialogFlavor.dishId,
  550. flavors:[],
  551. image:dialogFlavor.image,
  552. name:dialogFlavor.name
  553. })
  554. this.dialogFlavor.show = false
  555. }
  556. },
  557. //网络图片路径转换
  558. imgPathConvert(path){
  559. return imgPath(path)
  560. },
  561. //跳转到去结算界面
  562. toAddOrderPage(){
  563. if(this.cartData.length > 0){
  564. window.requestAnimationFrame(()=>{
  565. window.location.href ='/front/page/add-order.html'
  566. })
  567. }
  568. },
  569. toUserPage(){
  570. window.requestAnimationFrame(()=>{
  571. window.location.href= '/front/page/user.html'
  572. })
  573. },
  574. async dishDetails(item){
  575. //先清除对象数据,如果不行的话dialog使用v-if
  576. this.detailsDialog.item = {}
  577. this.setMealDialog.item = {}
  578. if(Array.isArray(item.flavors)){
  579. this.detailsDialog.item = item
  580. this.detailsDialog.show = true
  581. }else{
  582. //显示套餐的数据
  583. const res = await setMealDishDetailsApi(item.id)
  584. if(res.code === 1){
  585. this.setMealDialog.item = {...item,list:res.data}
  586. this.setMealDialog.show = true
  587. }else{
  588. this.$notify({ type:'warning', message:res.msg});
  589. }
  590. }
  591. }
  592. }
  593. })
  594. </script>
  595. </html>