feat: init
commit
edfeb770ff
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/dist/*
|
||||||
|
.local
|
||||||
|
.output.js
|
||||||
|
.github
|
||||||
|
.vscode
|
||||||
|
/node_modules/**
|
||||||
|
|
||||||
|
*.html
|
||||||
|
**/*.svg
|
||||||
|
**/*.sh
|
||||||
|
|
||||||
|
/public/**
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"printWidth": 160,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"bracketSameLine": true,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"semi": true,
|
||||||
|
"singleAttributePerLine": false,
|
||||||
|
"vueIndentScriptAndStyle": true,
|
||||||
|
"htmlWhitespaceSensitivity": "ignore"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"recommendations": ["Vue.volar"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEA2SOM6Heb+BNGha/ucoV+GopddM7ckyGWALhGPJp/Z7P5jgw6
|
||||||
|
NSJ1G/E7CFEukaLC50eupji9mA4o8Emtrgn8y7uMIc5lafHe0IPy+WA90PZyien4
|
||||||
|
0u7dD0NrEbKH41SIEuZFbGev0CgQJsxmkS8CmOytmglyJ0JDBpJD9tQLwSuG9kad
|
||||||
|
DrYPArQdQu+ZALt4gyG7m14c4mZ2hAcIUwNYqFY9g/HIp0q9al8SW3WqzkB1U7GS
|
||||||
|
kh3i/MwtUvZWPI16aKW4/tdUX7y8PPguHQ1MWLd6DI0iGo9tqTQt35o9ax41O+0S
|
||||||
|
EY4MgU1Q3XJaMrmrYUpZ2/Y4xJbHOHgyi6afzQIDAQABAoIBAGms4ovUgkSmZOD1
|
||||||
|
MU/s5eVWx4rsje7RHqa1CAHAkxbOQTq/eqiXX3U83qT6lXZtRvu2KCpfXO4eng/r
|
||||||
|
W6pi0/P3D4j4YOTBwNWsEdkJ3KvQ9QdnpiBJ/a3K+tW/FGEvp5XDGbBbefYNOWcY
|
||||||
|
fSZVQadZMFfSFwtCNUqCbq82nY3hkoFVGiQ9EHUlvNCQM4y5VeJuCPzsl8rzAsyo
|
||||||
|
gpkHyKxU/CNg+f5UuPwostR5eTXgkp6nlpa65yDK0szsww78keE/J1tOB0d4r+Oe
|
||||||
|
12ZVzYLQrzQwt2CwIGT9KkAUv7eO7ZTMDsG8MYNnRPGXKgjSZqBSW0MCq7ksz1/P
|
||||||
|
dHTJmSECgYEA9Q8VbnLkdk5NlRCNTONfjLhNUGmAqt/qLPi7tnJa0wfSpr3tg1Aj
|
||||||
|
AxnV455fT81vbDP8V8tGDNx+/d5jBkIsdsCYOMa6dqZr1HOfSgbH8wETtU9mbKdB
|
||||||
|
Gt/frdM3rkJvyd5RjoqMex4U7x4f1OWfThHVzvi8TzqfRSXNpbXBMdUCgYEA4tVa
|
||||||
|
TBQhwgnjMHl9OYrW1urtf2fKEGOZA/uGJI55O7IL2SoYnVjFUHjlE4D94K/hdijp
|
||||||
|
l2oFydD0GrWVkWULPvTdUFzMTRPH+SUfXbVqXBMJfHJYrRuZHsJBH2jIwIzu4LaA
|
||||||
|
hliletIdJUtK8mUvwEb+4TlVUwfCYqkveu1EuhkCgYAHjK5pV6rIJkNnmznvK3YP
|
||||||
|
HMJs/sMTAJDzT7pgtYcsxynrLyC5EefyOYKIX6GqELclCzjz73Q6AzT6VzaPw8wg
|
||||||
|
4HAQF7c43oml4uX+XtUcHGViCY8rO7/atxjp/v7RJITTIEE89fG7/UJB15i9c1GE
|
||||||
|
EzKWDL2oZzLu62o5d676/QKBgQDgiCBhvmvMDs18ZkW2d+BBzTpaKvqxTmVgs9EM
|
||||||
|
zpripFNmG21SE1T9Wy4mKEEl7/NVaxoObzxbkSKQbb4ntcV0BB4uNi1k/ner/zsV
|
||||||
|
H0aw7YcuUGHGuNLQx6h+1tIhB2BNv1lposXq1aFUETuWxOKHib8yYfY7wiqATshY
|
||||||
|
/hRRwQKBgCkT2Wt/XjbXLCpX1viEJOLzYYQkrNyPvruXknCnQQ+0/cq4LoRqWZZR
|
||||||
|
4RjS0RkoOF4vM38u/hgICiUUCR4bYUy/4O7uhNu5tDle6lIeB+ZxVpRRedE0OfQT
|
||||||
|
tCpQd0yN9iONBlGyfAtpq7oNzuXgsl1OR4usZ8wCinfImChAl6wv
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
// biome-ignore lint: disable
|
||||||
|
export {}
|
||||||
|
|
||||||
|
/* prettier-ignore */
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
BackButton: typeof import('./src/components/back-button/index.vue')['default']
|
||||||
|
Carte: typeof import('./src/components/restaurant-cart/carte.vue')['default']
|
||||||
|
CheckoutBtn: typeof import('./src/components/restaurant-cart/checkout-btn.vue')['default']
|
||||||
|
ChooseLoation: typeof import('./src/components/checkout/chooseLoation.vue')['default']
|
||||||
|
ChooseLocation: typeof import('./src/components/checkout/chooseLocation.vue')['default']
|
||||||
|
ChoosePeople: typeof import('./src/components/checkout/choosePeople.vue')['default']
|
||||||
|
ChooseTime: typeof import('./src/components/checkout/chooseTime.vue')['default']
|
||||||
|
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||||
|
HealthCare: typeof import('./src/components/shopping-cart/health-care.vue')['default']
|
||||||
|
NutActionSheet: typeof import('@nutui/nutui')['ActionSheet']
|
||||||
|
NutBadge: typeof import('@nutui/nutui')['Badge']
|
||||||
|
NutButton: typeof import('@nutui/nutui')['Button']
|
||||||
|
NutCalendar: typeof import('@nutui/nutui')['Calendar']
|
||||||
|
NutCard: typeof import('@nutui/nutui')['Card']
|
||||||
|
NutCell: typeof import('@nutui/nutui')['Cell']
|
||||||
|
NutCellGroup: typeof import('@nutui/nutui')['CellGroup']
|
||||||
|
NutCheckbox: typeof import('@nutui/nutui')['Checkbox']
|
||||||
|
NutCheckboxGroup: typeof import('@nutui/nutui')['CheckboxGroup']
|
||||||
|
NutDivider: typeof import('@nutui/nutui')['Divider']
|
||||||
|
NutDrag: typeof import('@nutui/nutui')['Drag']
|
||||||
|
NutElevator: typeof import('@nutui/nutui')['Elevator']
|
||||||
|
NutForm: typeof import('@nutui/nutui')['Form']
|
||||||
|
NutFormItem: typeof import('@nutui/nutui')['FormItem']
|
||||||
|
NutGrid: typeof import('@nutui/nutui')['Grid']
|
||||||
|
NutGridItem: typeof import('@nutui/nutui')['GridItem']
|
||||||
|
NutImage: typeof import('@nutui/nutui')['Image']
|
||||||
|
NutImagePreview: typeof import('@nutui/nutui')['ImagePreview']
|
||||||
|
NutInput: typeof import('@nutui/nutui')['Input']
|
||||||
|
NutInputNumber: typeof import('@nutui/nutui')['InputNumber']
|
||||||
|
NutList: typeof import('@nutui/nutui')['List']
|
||||||
|
NutMenu: typeof import('@nutui/nutui')['Menu']
|
||||||
|
NutMenuItem: typeof import('@nutui/nutui')['MenuItem']
|
||||||
|
NutNavbar: typeof import('@nutui/nutui')['Navbar']
|
||||||
|
NutPopup: typeof import('@nutui/nutui')['Popup']
|
||||||
|
NutPrice: typeof import('@nutui/nutui')['Price']
|
||||||
|
NutRadio: typeof import('@nutui/nutui')['Radio']
|
||||||
|
NutRadioGroup: typeof import('@nutui/nutui')['RadioGroup']
|
||||||
|
NutSearchbar: typeof import('@nutui/nutui')['Searchbar']
|
||||||
|
NutSticky: typeof import('@nutui/nutui')['Sticky']
|
||||||
|
NutSwiper: typeof import('@nutui/nutui')['Swiper']
|
||||||
|
NutSwiperItem: typeof import('@nutui/nutui')['SwiperItem']
|
||||||
|
NutSwitch: typeof import('@nutui/nutui')['Switch']
|
||||||
|
NutTabbar: typeof import('@nutui/nutui')['Tabbar']
|
||||||
|
NutTabbarItem: typeof import('@nutui/nutui')['TabbarItem']
|
||||||
|
NutTabPane: typeof import('@nutui/nutui')['TabPane']
|
||||||
|
NutTabs: typeof import('@nutui/nutui')['Tabs']
|
||||||
|
NutTextarea: typeof import('@nutui/nutui')['Textarea']
|
||||||
|
NutToast: typeof import('@nutui/nutui')['Toast']
|
||||||
|
NutUploader: typeof import('@nutui/nutui')['Uploader']
|
||||||
|
NutVideo: typeof import('@nutui/nutui')['Video']
|
||||||
|
Product: typeof import('./src/components/shopping-cart/product.vue')['default']
|
||||||
|
ResaurantBtn: typeof import('./src/components/restaurant-cart/resaurant-btn.vue')['default']
|
||||||
|
RestaurantCart: typeof import('./src/components/restaurant-cart/index.vue')['default']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
Share: typeof import('./src/components/shopping-cart/share.vue')['default']
|
||||||
|
ShoppingCart: typeof import('./src/components/shopping-cart/index.vue')['default']
|
||||||
|
SvgComponent: typeof import('./src/components/SvgComponent.vue')['default']
|
||||||
|
SvgIcon: typeof import('./src/components/svg-icon/SvgIcon.vue')['default']
|
||||||
|
Tabbar: typeof import('./src/components/tabbar/index.vue')['default']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||||
|
<meta charset="utf-8" name="referrer" content="strict-origin-when-cross-origin" />
|
||||||
|
<!-- WX JS SDK 微信小程序一定要引入这个文件 可以自己去官方下载最新的-->
|
||||||
|
<script type="text/javascript" src="/js/jweixin-1.6.0.js"></script>
|
||||||
|
<script type="text/javascript" src="/js/uni.webview.1.5.6.js" defer></script>
|
||||||
|
<!-- <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var vConsole = new window.VConsole();
|
||||||
|
</script> -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"name": "vue-app-template",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --host 0.0.0.0",
|
||||||
|
"build": "vue-tsc -b && vite build",
|
||||||
|
"upload": "bash ./upload.sh",
|
||||||
|
"build-and-upload": "pnpm run build && pnpm run upload",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"check-env": "node ./scripts/checkVersions.cjs"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nutui/nutui": "^4.3.13",
|
||||||
|
"@types/crypto-js": "^4.2.2",
|
||||||
|
"@types/node": "^22.10.1",
|
||||||
|
"@unocss/reset": "^66.3.2",
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
|
"echarts": "^5.6.0",
|
||||||
|
"lucide-vue-next": "^0.525.0",
|
||||||
|
"pinia": "^2.3.0",
|
||||||
|
"pinia-plugin-persistedstate": "^4.1.3",
|
||||||
|
"semver": "^7.6.3",
|
||||||
|
"vue": "^3.5.13",
|
||||||
|
"vue-echarts": "^7.0.3",
|
||||||
|
"vue-router": "4",
|
||||||
|
"vue-virtual-draglist": "^3.3.8"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@iconify-json/carbon": "^1.2.8",
|
||||||
|
"@nutui/auto-import-resolver": "^1.0.0",
|
||||||
|
"@types/qs": "^6.9.17",
|
||||||
|
"@unocss-applet/preset-rem-rpx": "^0.9.0",
|
||||||
|
"@unocss/preset-wind": "^0.65.2",
|
||||||
|
"@vitejs/plugin-basic-ssl": "^1.2.0",
|
||||||
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
"prettier": "3.4.2",
|
||||||
|
"sass-embedded": "^1.86.0",
|
||||||
|
"svg-sprite-loader": "^6.0.11",
|
||||||
|
"typescript": "~5.6.2",
|
||||||
|
"unocss": "^0.65.2",
|
||||||
|
"unplugin-auto-import": "^19.3.0",
|
||||||
|
"unplugin-vue-components": "^28.8.0",
|
||||||
|
"vite": "^6.0.1",
|
||||||
|
"vue-tsc": "^2.1.10"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=22.11.0",
|
||||||
|
"pnpm": ">=9.13.2"
|
||||||
|
},
|
||||||
|
"preinstall": "npx only-allow pnpm"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
|
||||||
|
// /plugins/svgBuilder.ts
|
||||||
|
import {readFileSync, readdirSync} from 'fs'
|
||||||
|
import {join as pathJoin} from 'path'
|
||||||
|
import {Plugin} from 'vite'
|
||||||
|
|
||||||
|
let idPrefix = ''
|
||||||
|
const svgTitle = /<svg([^>+].*?)>/
|
||||||
|
const clearHeightWidth = /(width|height)="([^>+].*?)"/g
|
||||||
|
const clearFill = /fill="[^>+].*?"/g;
|
||||||
|
|
||||||
|
const hasViewBox = /(viewBox="[^>+].*?")/g
|
||||||
|
|
||||||
|
const clearReturn = /(\r)|(\n)/g
|
||||||
|
|
||||||
|
const findSvgFile = (dir: string) => {
|
||||||
|
const svgRes: string[] = []
|
||||||
|
const directory = readdirSync(dir, {withFileTypes: true})
|
||||||
|
for (const dirent of directory) {
|
||||||
|
if (dirent?.isDirectory()) {
|
||||||
|
svgRes.push(...findSvgFile(pathJoin(dir, dirent.name, '/')))
|
||||||
|
} else {
|
||||||
|
const svg = readFileSync(pathJoin(dir, dirent.name))
|
||||||
|
.toString()
|
||||||
|
.replace(clearReturn, '')
|
||||||
|
.replace(clearFill,'')
|
||||||
|
.replace(svgTitle, (_$1: string, $2: string) => {
|
||||||
|
let width = '0'
|
||||||
|
let height = '0'
|
||||||
|
let content = $2.replace(
|
||||||
|
clearHeightWidth,
|
||||||
|
(_s1, s2:string, s3:string) => {
|
||||||
|
if (s2 === 'width') {
|
||||||
|
width = s3
|
||||||
|
} else if (s2 === 'height') {
|
||||||
|
height = s3
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (!hasViewBox.test($2)) {
|
||||||
|
content += `viewBox="0 0 ${width} ${height}"`
|
||||||
|
}
|
||||||
|
return `<symbol id="${idPrefix}-${dirent.name.replace(
|
||||||
|
'.svg',
|
||||||
|
''
|
||||||
|
)}" ${content}>`
|
||||||
|
})
|
||||||
|
.replace('</svg>', '</symbol>')
|
||||||
|
svgRes.push(svg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return svgRes
|
||||||
|
}
|
||||||
|
|
||||||
|
const svgBuilder = (path: string, prefix = 'icon'): Plugin => {
|
||||||
|
idPrefix = prefix
|
||||||
|
const res = findSvgFile(path)
|
||||||
|
return {
|
||||||
|
name: 'svg-transform',
|
||||||
|
transformIndexHtml(html) {
|
||||||
|
return html.replace(
|
||||||
|
'<body>',
|
||||||
|
`<body><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">${res.join('')}</svg>`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default svgBuilder
|
||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,18 @@
|
||||||
|
const semver = require('semver')
|
||||||
|
const { engines } = require('../package')// 这里的package是你的package.json文件路径
|
||||||
|
const version = engines.node
|
||||||
|
|
||||||
|
if (!semver.satisfies(process.version, version)) {
|
||||||
|
console.log(
|
||||||
|
[
|
||||||
|
'node环境变量版本错误',
|
||||||
|
'你的node环境启动位置' + process.execPath + '.',
|
||||||
|
'要求环境版本' + version,
|
||||||
|
'你的环境版本' + process.version
|
||||||
|
].join('\n')
|
||||||
|
)
|
||||||
|
process.exit(1)
|
||||||
|
}else{
|
||||||
|
console.log(`echo check environment successfully`)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col h-screen w-screen pb-safe">
|
||||||
|
<router-view v-slot="{ Component,route }">
|
||||||
|
<keep-alive :include="include" :exclude="excludes">
|
||||||
|
<component :is="Component" :key="route.path" class="flex-auto overflow-auto"/>
|
||||||
|
</keep-alive>
|
||||||
|
</router-view>
|
||||||
|
<router-view name="tabbar">
|
||||||
|
</router-view>
|
||||||
|
<router-view name="backButton"></router-view>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { excludes } from '@/router/keepAlive'
|
||||||
|
|
||||||
|
const include:string[] = []
|
||||||
|
|
||||||
|
// window.addEventListener('message', function(event) {
|
||||||
|
// // event.data 包含了应用发送的消息
|
||||||
|
// const message = event.data;
|
||||||
|
// console.log('收到应用消息:', message);
|
||||||
|
// // 在这里处理接收到的消息
|
||||||
|
// });
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* @Author: HideInMatrix
|
||||||
|
* @Date: 2024-07-15
|
||||||
|
* @LastEditors: error: git config user.name & please set dead value or install git
|
||||||
|
* @LastEditTime: 2024-09-01
|
||||||
|
* @Description: 请求封装
|
||||||
|
* @FilePath: /free-music-react/src/lib/customFetch.ts
|
||||||
|
*/
|
||||||
|
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
|
||||||
|
|
||||||
|
interface FetchOptions extends RequestInit {
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApiResponse {
|
||||||
|
result?: unknown;
|
||||||
|
error?: string;
|
||||||
|
code?: number;
|
||||||
|
success?: boolean;
|
||||||
|
message?:string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiClient = (method: HttpMethod) => {
|
||||||
|
return async (
|
||||||
|
url: string,
|
||||||
|
data?: unknown,
|
||||||
|
options: FetchOptions = {}
|
||||||
|
): Promise<ApiResponse> => {
|
||||||
|
const config: FetchOptions = {
|
||||||
|
method,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (method !== "GET" && data) {
|
||||||
|
config.body = JSON.stringify(data);
|
||||||
|
} else if (method === "GET" && data) {
|
||||||
|
const _params = [];
|
||||||
|
for (const [key, value] of Object.entries(data)) {
|
||||||
|
_params.push(`${key}=${value}`);
|
||||||
|
}
|
||||||
|
url += `?${_params.join("&")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${url}`, config);
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return {
|
||||||
|
error: result.message || "Request failed",
|
||||||
|
code: response.status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRequest = apiClient("GET");
|
||||||
|
export const postRequest = apiClient("POST");
|
||||||
|
export const putRequest = apiClient("PUT");
|
||||||
|
export const deleteRequest = apiClient("DELETE");
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// 对指定请求链接进行加密
|
||||||
|
|
||||||
|
import { AxiosRequestConfig } from "axios";
|
||||||
|
import { useUserStore } from "@/store/user";
|
||||||
|
|
||||||
|
export const handleUrl = async (config: (AxiosRequestConfig & {unEncrypt?: boolean})) => {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
if(userStore.getToken){
|
||||||
|
config.headers!!["Authorization"] = `Bearer ${userStore.getToken}`
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
const baseUrl = ''
|
||||||
|
|
||||||
|
export const getMapSearch = () => {
|
||||||
|
return `http://api.tianditu.gov.cn/v2/search`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLocationByReverseGeography = () => {
|
||||||
|
return `http://api.tianditu.gov.cn/geocoder`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getAdministrative =() => {
|
||||||
|
return `http://api.tianditu.gov.cn/v2/administrative`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getProductCategory = () => {
|
||||||
|
return `${baseUrl}/api/mall/category/list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getMallRecommend = () => {
|
||||||
|
return `${baseUrl}/api/mall/recommend`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getUserAddressList = () => {
|
||||||
|
return `${baseUrl}/api/user/address/list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setUserDefaultAddress = () => {
|
||||||
|
return `${baseUrl}/api/user/address/set-default`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getProductInfo = () => {
|
||||||
|
return `${baseUrl}/api/product/detail`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getNotifyList = () => {
|
||||||
|
return `${baseUrl}/api/notice/list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRestaurantFoodList = () => {
|
||||||
|
return `${baseUrl}/api/product/simple-list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRestaurantFoodDetail = () => {
|
||||||
|
return `${baseUrl}/api/meal/product/detail`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRestaurantFoodSet = () => {
|
||||||
|
return `${baseUrl}/api/product/setmeal-list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLessonCategory = () => {
|
||||||
|
return `${baseUrl}/api/lesson/category`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLessonList = () => {
|
||||||
|
return `${baseUrl}/api/lesson/list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCourseDetail = () => {
|
||||||
|
return `${baseUrl}/api/course/detail`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLessonCatalog = () => {
|
||||||
|
return `${baseUrl}/api/lesson/catalog`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getNursingHomeList = () => {
|
||||||
|
return `${baseUrl}/api/nursing-home/list`
|
||||||
|
}
|
||||||
|
export const getNursingDetail = () => {
|
||||||
|
return `${baseUrl}/api/nursing/detail`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTravelList = () => {
|
||||||
|
return `${baseUrl}/api/travel/list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getHospitalCompanionList = () =>{
|
||||||
|
return `${baseUrl}/api/nursing/hospital-companion/list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServiceDetail = () =>{
|
||||||
|
return `${baseUrl}/api/service/detail`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getHousekeepingCleaningList = () =>{
|
||||||
|
return `${baseUrl}/api/housekeeping/cleaning/list`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getHousekeepingCleaningDetail = () =>{
|
||||||
|
return `${baseUrl}/api/housekeeping/cleaning/detail`
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
// Generated by unplugin-auto-import
|
||||||
|
// biome-ignore lint: disable
|
||||||
|
export {}
|
||||||
|
declare global {
|
||||||
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
|
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||||
|
const computed: typeof import('vue')['computed']
|
||||||
|
const createApp: typeof import('vue')['createApp']
|
||||||
|
const createPinia: typeof import('pinia')['createPinia']
|
||||||
|
const customRef: typeof import('vue')['customRef']
|
||||||
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||||
|
const defineComponent: typeof import('vue')['defineComponent']
|
||||||
|
const defineStore: typeof import('pinia')['defineStore']
|
||||||
|
const effectScope: typeof import('vue')['effectScope']
|
||||||
|
const getActivePinia: typeof import('pinia')['getActivePinia']
|
||||||
|
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||||
|
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||||
|
const h: typeof import('vue')['h']
|
||||||
|
const inject: typeof import('vue')['inject']
|
||||||
|
const isProxy: typeof import('vue')['isProxy']
|
||||||
|
const isReactive: typeof import('vue')['isReactive']
|
||||||
|
const isReadonly: typeof import('vue')['isReadonly']
|
||||||
|
const isRef: typeof import('vue')['isRef']
|
||||||
|
const mapActions: typeof import('pinia')['mapActions']
|
||||||
|
const mapGetters: typeof import('pinia')['mapGetters']
|
||||||
|
const mapState: typeof import('pinia')['mapState']
|
||||||
|
const mapStores: typeof import('pinia')['mapStores']
|
||||||
|
const mapWritableState: typeof import('pinia')['mapWritableState']
|
||||||
|
const markRaw: typeof import('vue')['markRaw']
|
||||||
|
const nextTick: typeof import('vue')['nextTick']
|
||||||
|
const onActivated: typeof import('vue')['onActivated']
|
||||||
|
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||||
|
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
||||||
|
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
||||||
|
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||||
|
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||||
|
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||||
|
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||||
|
const onMounted: typeof import('vue')['onMounted']
|
||||||
|
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||||
|
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||||
|
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||||
|
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||||
|
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||||
|
const onUpdated: typeof import('vue')['onUpdated']
|
||||||
|
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||||
|
const provide: typeof import('vue')['provide']
|
||||||
|
const reactive: typeof import('vue')['reactive']
|
||||||
|
const readonly: typeof import('vue')['readonly']
|
||||||
|
const ref: typeof import('vue')['ref']
|
||||||
|
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||||
|
const setActivePinia: typeof import('pinia')['setActivePinia']
|
||||||
|
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
|
||||||
|
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||||
|
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||||
|
const shallowRef: typeof import('vue')['shallowRef']
|
||||||
|
const storeToRefs: typeof import('pinia')['storeToRefs']
|
||||||
|
const toRaw: typeof import('vue')['toRaw']
|
||||||
|
const toRef: typeof import('vue')['toRef']
|
||||||
|
const toRefs: typeof import('vue')['toRefs']
|
||||||
|
const toValue: typeof import('vue')['toValue']
|
||||||
|
const triggerRef: typeof import('vue')['triggerRef']
|
||||||
|
const unref: typeof import('vue')['unref']
|
||||||
|
const useAttrs: typeof import('vue')['useAttrs']
|
||||||
|
const useCssModule: typeof import('vue')['useCssModule']
|
||||||
|
const useCssVars: typeof import('vue')['useCssVars']
|
||||||
|
const useId: typeof import('vue')['useId']
|
||||||
|
const useLink: typeof import('vue-router')['useLink']
|
||||||
|
const useModel: typeof import('vue')['useModel']
|
||||||
|
const useRoute: typeof import('vue-router')['useRoute']
|
||||||
|
const useRouter: typeof import('vue-router')['useRouter']
|
||||||
|
const useSlots: typeof import('vue')['useSlots']
|
||||||
|
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
||||||
|
const watch: typeof import('vue')['watch']
|
||||||
|
const watchEffect: typeof import('vue')['watchEffect']
|
||||||
|
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||||
|
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||||
|
}
|
||||||
|
// for type re-export
|
||||||
|
declare global {
|
||||||
|
// @ts-ignore
|
||||||
|
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||||
|
import('vue')
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<template>
|
||||||
|
<div class="block">
|
||||||
|
<i v-html="content"></i>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
|
||||||
|
content:{
|
||||||
|
type:String,
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<template>
|
||||||
|
<nut-drag direction="y" attract :style="[props.bottom ? {bottom:props.bottom} : {top:props.top}]" class="rounded-full bg-[#fff] border-solid border-black border-[3rpx] left-[30rpx]" style="z-index: 999 !important;">
|
||||||
|
<ChevronLeft class="w-[88rpx] h-[88rpx] text-black" :stroke-width="2" @click="goBack"/>
|
||||||
|
</nut-drag>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ChevronLeft } from 'lucide-vue-next';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
bottom:{
|
||||||
|
type:String,
|
||||||
|
default:""
|
||||||
|
},
|
||||||
|
top:{
|
||||||
|
type:String,
|
||||||
|
default:"8vh"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
<template>
|
||||||
|
<nut-action-sheet v-model:visible="innerShow">
|
||||||
|
<div class="flex flex-col bg-[#F5F5F5]">
|
||||||
|
<div class="relative py-[32rpx] text-center bg-white">
|
||||||
|
<div class="text-[36rpx] font-500">选择收货地址</div>
|
||||||
|
<div class="w-[60rpx] h-[60rpx] bg-[#f5f5f5] rounded-full absolute top-[20rpx] right-[20rpx] flex items-center justify-center" @click="handleClose">
|
||||||
|
<X class="text-[25rpx]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-[30rpx] py-[20rpx] min-h-0 flex-auto overflow-auto">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in recvAddrList"
|
||||||
|
:key="index"
|
||||||
|
class="items-center justify-between h-[210rpx] rounded-[24rpx] bg-white pt-[30rpx] pl-[30rpx] pb-[22rpx] pr-[34rpx] flex mt-[30rpx]"
|
||||||
|
:class="{ 'active-address': item.isDefault }"
|
||||||
|
@click="handleSelectAddress(item)">
|
||||||
|
<div class="flex flex-col justify-evenly flex-1 h-full">
|
||||||
|
<div class="text-[36rpx] font-600">{{ item.fullAddress }}</div>
|
||||||
|
<div class="text-[32rpx] text-[#333] font-400 flex items-center mt-[14rpx]">
|
||||||
|
<div class="mr-[20rpx]">{{ item.name }}</div>
|
||||||
|
<div>{{ item.phone }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="h-[125rpx] py-[12rpx] mr-[30rpx]">
|
||||||
|
<div class="border-r-[#CCCCCC] border-dashed border-r-[2rpx] h-full w-[1rpx]"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col items-center" @click="handleEditAddress(item)">
|
||||||
|
<PencilLine class="w-[48rpx] h-[48rpx] text-[#29bebb]" />
|
||||||
|
<div class="text-[#28BEBB] text-[32rpx] font-400 mt-[8rpx]">修改</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Check class="text-[#fff] absolute bottom-[-10rpx] right-[-5rpx] font-700" v-if="item.isDefault" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-[30rpx] py-[16rpx] bg-white">
|
||||||
|
<div class="pb-safe">
|
||||||
|
<div class="flex items-center justify-center bg-[#28BEBB] rounded-[20rpx] px-[80rpx] py-[28rpx]" @click="toAddAddressPage">
|
||||||
|
<CirclePlus class="text-white mr-[16rpx]" fill="#fff" stroke="#29bebb" :stroke-width="2"/>
|
||||||
|
<span class="text-white">新增收货地址</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nut-action-sheet>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useUserStore } from "@/store/user";
|
||||||
|
import { X, PencilLine, CirclePlus, Check } from "lucide-vue-next";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const innerShow = computed({
|
||||||
|
get() {
|
||||||
|
return props.show;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
emit("update:show", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const recvAddrList = computed(() => userStore.recvAddrList);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:show"]);
|
||||||
|
|
||||||
|
const handleEditAddress = (item: any) => {
|
||||||
|
router.push({ path: "/mine/address", query: { id: item.id } });
|
||||||
|
};
|
||||||
|
|
||||||
|
const toAddAddressPage = () => {
|
||||||
|
router.push({ path: "/mine/add/address" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectAddress = (item: any) => {
|
||||||
|
userStore.setDefaultAddress(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
emit("update:show", false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.active-address {
|
||||||
|
outline: 2px solid #000000;
|
||||||
|
position: relative;
|
||||||
|
& ::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: 15px solid;
|
||||||
|
border-color: transparent #000 #000 transparent;
|
||||||
|
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
<template>
|
||||||
|
<nut-action-sheet v-model:visible="innerShow">
|
||||||
|
<div class="flex flex-col bg-[#F5F5F5]">
|
||||||
|
<div class="relative py-[32rpx] text-center bg-white">
|
||||||
|
<div class="text-[36rpx] font-500">选择被护理人</div>
|
||||||
|
<div class="w-[60rpx] h-[60rpx] bg-[#f5f5f5] rounded-full absolute top-[20rpx] right-[20rpx] flex items-center justify-center" @click="handleClose">
|
||||||
|
<X class="text-[25rpx]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-[30rpx] py-[20rpx] min-h-0 flex-auto overflow-auto">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in recvAddrList"
|
||||||
|
:key="index"
|
||||||
|
class="items-center justify-between h-[210rpx] rounded-[24rpx] bg-white p-[30rpx] flex mt-[30rpx]"
|
||||||
|
:class="{ 'active-address': item.isDefault }"
|
||||||
|
@click="handleSelectAddress(item)">
|
||||||
|
<div class="flex flex-col justify-evenly flex-1 h-full text-[32rpx] font-400 text-[#333]">
|
||||||
|
<div class="flex items-center mt-[14rpx]">
|
||||||
|
<div class="w-[72rpx] h-[38rpx] rounded-[10rpx] bg-[#e8f2ff] text-[26rpx] text-[#1D86FF] flex items-center justify-center mr-[10rpx]" v-if="item.isDefault">默认</div>
|
||||||
|
<div class="mr-[20rpx]">{{ item.name }}</div>
|
||||||
|
</div>
|
||||||
|
<div>{{ item.phone }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="h-[125rpx] py-[12rpx] mr-[30rpx]">
|
||||||
|
<div class="border-r-[#CCCCCC] border-dashed border-r-[2rpx] h-full w-[1rpx]"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col items-center" @click="handleEditAddress(item)">
|
||||||
|
<PencilLine class="w-[48rpx] h-[48rpx] text-[#29bebb]" />
|
||||||
|
<div class="text-[#28BEBB] text-[32rpx] font-400 mt-[8rpx]">修改</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Check class="text-[#fff] absolute bottom-[-10rpx] right-[-5rpx] font-700" v-if="item.isDefault" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-[30rpx] py-[16rpx] bg-white">
|
||||||
|
<div class="pb-safe">
|
||||||
|
<div class="flex items-center justify-center bg-[#28BEBB] rounded-[20rpx] px-[80rpx] py-[28rpx]" @click="toAddAddressPage">
|
||||||
|
<CirclePlus class="text-white mr-[16rpx] size-[54rpx]" fill="#fff" stroke="#29bebb" :stroke-width="2"/>
|
||||||
|
<span class="text-white text-[44rpx]">新增被护理人</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nut-action-sheet>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useUserStore } from "@/store/user";
|
||||||
|
import { X, PencilLine, CirclePlus, Check } from "lucide-vue-next";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const innerShow = computed({
|
||||||
|
get() {
|
||||||
|
return props.show;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
emit("update:show", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const recvAddrList = ref([
|
||||||
|
{ name: "王大力(女,67岁)", phone: "310108196005127765", isDefault: true },
|
||||||
|
{ name: "王小力(女,67岁)", phone: "310108196005127765", isDefault: false },
|
||||||
|
]);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:show"]);
|
||||||
|
|
||||||
|
const handleEditAddress = (item: any) => {
|
||||||
|
router.push({ path: "/mine/add/paramedic", query: { id: item.id } });
|
||||||
|
};
|
||||||
|
|
||||||
|
const toAddAddressPage = () => {
|
||||||
|
router.push({ path: "/mine/add/paramedic" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectAddress = (item: any) => {
|
||||||
|
|
||||||
|
recvAddrList.value = recvAddrList.value.map(item => {
|
||||||
|
if (item.isDefault) {
|
||||||
|
item.isDefault = false;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
item.isDefault = true;
|
||||||
|
// userStore.setDefaultAddress(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
emit("update:show", false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.active-address {
|
||||||
|
outline: 2px solid #000000;
|
||||||
|
position: relative;
|
||||||
|
& ::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: 15px solid;
|
||||||
|
border-color: transparent #000 #000 transparent;
|
||||||
|
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
<template>
|
||||||
|
<nut-action-sheet v-model:visible="innerShow">
|
||||||
|
<div class="flex flex-col bg-[#F5F5F5]">
|
||||||
|
<div class="relative py-[32rpx] text-center bg-white">
|
||||||
|
<div class="text-[36rpx] font-500">选择服务时长</div>
|
||||||
|
<div class="w-[60rpx] h-[60rpx] bg-[#f5f5f5] rounded-full absolute top-[20rpx] right-[20rpx] flex items-center justify-center" @click="handleClose">
|
||||||
|
<X class="text-[25rpx]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-[30rpx] py-[20rpx] min-h-0 flex-auto overflow-auto">
|
||||||
|
<nut-radio-group v-model="chooseTime" class="flex time-radio-group" direction="horizontal">
|
||||||
|
<nut-radio v-for="item in timeList" :key="item.value" :label="item.value" shape="button">{{ item.label }}</nut-radio>
|
||||||
|
</nut-radio-group>
|
||||||
|
|
||||||
|
<div class="text-[32rpx] text-[#999AA3] mt-[20rpx]">2小时适合面积≤50平米房屋</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-[30rpx] py-[16rpx] bg-white">
|
||||||
|
<div class="pb-safe">
|
||||||
|
<div class="flex items-center justify-center bg-[#28BEBB] rounded-[20rpx] px-[80rpx] py-[28rpx]" @click="submit">
|
||||||
|
<span class="text-white">确定</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nut-action-sheet>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { X } from "lucide-vue-next";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const innerShow = computed({
|
||||||
|
get() {
|
||||||
|
return props.show;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
emit("update:show", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const chooseTime = ref(2);
|
||||||
|
|
||||||
|
const timeList = [
|
||||||
|
{
|
||||||
|
label: "2小时",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "3小时",
|
||||||
|
value: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "4小时",
|
||||||
|
value: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "5小时",
|
||||||
|
value: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "6小时",
|
||||||
|
value: 6,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:show",'onGetTime']);
|
||||||
|
|
||||||
|
const submit = () => {
|
||||||
|
handleClose();
|
||||||
|
emit("onGetTime",chooseTime.value)
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
emit("update:show", false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.active-address {
|
||||||
|
outline: 2px solid #000000;
|
||||||
|
position: relative;
|
||||||
|
& ::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: 15px solid;
|
||||||
|
border-color: transparent #000 #000 transparent;
|
||||||
|
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-radio-group {
|
||||||
|
--nut-radio-button-padding: 13px 32px;
|
||||||
|
--nut-radio-button-border-radius: 5px;
|
||||||
|
--nut-radio-label-font-active-color:#0AB3B0;
|
||||||
|
--nut-radio-label-button-border-color: #28BEBB;
|
||||||
|
--nut-radio-label-button-background: #e9f8f8;
|
||||||
|
--nut-radio-button-font-size:18px;
|
||||||
|
|
||||||
|
:deep(.nut-radio__button){
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<nut-list v-if="carte.length > 0" :list-data="carte" @scroll-bottom="onScrollBottom" class="mt-[30rpx] flex-1 min-h-0 overflow-auto">
|
||||||
|
<template #default="{ item }">
|
||||||
|
<div class="bg-white mx-[30rpx] rounded-[20rpx] flex mb-[30rpx]">
|
||||||
|
<img :src="item.cover" alt="food" class="h-[176rpx] aspect-square rounded-[20rpx_0_0_20rpx] object-cover" />
|
||||||
|
<div class="px-[20rpx] flex-auto flex flex-col justify-between">
|
||||||
|
<p class="text-[40rpx] font-500">{{ item.name }}</p>
|
||||||
|
<p class="text-[30rpx] font-400 text-[#666] mb-[26rpx] mt-[10rpx]">{{ item.desc }}</p>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-baseline">
|
||||||
|
<nut-price :price="item.price" :decimal-places="2" size="normal" class="font-600" />
|
||||||
|
<span class="text-[28rpx] font-400 text-[#adafaf]">/份</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nut-input-number v-model="item.count" :readonly="true" @reduce="(event) => handleMinus(event, item)" @add="handlePlus(item)" :min="0">
|
||||||
|
<template #left-icon>
|
||||||
|
<div class="w-[52rpx] h-[52rpx] bg-white rounded-full flex items-center justify-center border-[#28BEBB] border-[4rpx] border-solid">
|
||||||
|
<Minus :stroke-width="3" class="text-[#28BEBB]" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #right-icon>
|
||||||
|
<div class="w-[52rpx] h-[52rpx] bg-[#28BEBB] rounded-full flex items-center justify-center">
|
||||||
|
<Plus :stroke-width="3" class="text-white" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</nut-input-number>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</nut-list>
|
||||||
|
<div v-else class="flex-1 min-h-0 overflow-auto flex items-center justify-center">
|
||||||
|
<p class="text-[32rpx] font-500">暂无商品</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Plus, Minus } from "lucide-vue-next";
|
||||||
|
import { useShoppingCartStore } from "@/store/shoppingCart";
|
||||||
|
|
||||||
|
const shoppingCartStore = useShoppingCartStore();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
carte: {
|
||||||
|
type: Array as PropType<any[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onScrollBottom = () => {
|
||||||
|
console.log("onScrollBottom");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMinus = (event: any, item: any) => {
|
||||||
|
const orderCount = Number(item.count) - 1;
|
||||||
|
if(orderCount <= 0){
|
||||||
|
shoppingCartStore.removeShoppingCart(item.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePlus = (item: any) => {
|
||||||
|
// console.log("handlePlus", item);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.nut-input-number {
|
||||||
|
--nut-inputnumber-input-background-color: #fff;
|
||||||
|
--nut-inputnumber-input-margin: 0;
|
||||||
|
--nut-inputnumber-input-font-size: 18px;
|
||||||
|
--nut-inputnumber-input-width: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<template>
|
||||||
|
<div class="h-[120rpx] rounded-full bg-[#25262A] flex">
|
||||||
|
<nut-badge :value="shoppingCartTotal" top="10" right="5" @click="showShoppingCart">
|
||||||
|
<img src="/images/checkout/basket.png" alt="" class="w-[100rpx] h-[100rpx] ml-[30rpx] my-[10rpx]" />
|
||||||
|
</nut-badge>
|
||||||
|
<div class="flex-1 min-w-0 flex flex-col justify-center ml-[6rpx]">
|
||||||
|
<nut-price :price="shoppingCartTotalPrice" size="normal" class="font-700 custom-price mb-[6rpx]" />
|
||||||
|
<div class="flex items-center text-white text-[26rpx]">
|
||||||
|
<div class="mr-[10rpx]">含运费 ¥{{ shippingFee }}</div>
|
||||||
|
<div>打包费 ¥{{ packingFee }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checkout-button w-[224rpx] relative text-white flex items-center justify-center" @click="handleCheckoutBtn">
|
||||||
|
<div class="text-white z-2 text-[40rpx] font-600">去结算</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { packingFee, shippingFee } from "@/composables/useRestaurant";
|
||||||
|
import { useShoppingCartStore } from "@/store/shoppingCart";
|
||||||
|
|
||||||
|
const shoppingCartStore = useShoppingCartStore();
|
||||||
|
const shoppingCartTotal = computed(() => {
|
||||||
|
return shoppingCartStore.getShoppingCartByRestaurant.reduce((total, item) => total + Number(item.count), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const shoppingCartTotalPrice = computed(() => {
|
||||||
|
return shoppingCartStore.getShoppingCartByRestaurant.reduce((total, item) => total + item.price * item.count, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["showShoppingCart","handleCheckoutBtn"]);
|
||||||
|
const showShoppingCart = () => {
|
||||||
|
emit("showShoppingCart");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCheckoutBtn = () => {
|
||||||
|
emit("handleCheckoutBtn");
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.custom-price {
|
||||||
|
--nut-price-symbol-medium-size: 18px;
|
||||||
|
--nut-price-decimal-medium-size: 18px;
|
||||||
|
--nut-price-medium-size: 24px;
|
||||||
|
--nut-primary-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkout-button {
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 50px;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: 20px 100% 100% 20px;
|
||||||
|
background: #f68e1d;
|
||||||
|
transform: skewX(-15deg);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
border-radius: 0 113px 113px 0;
|
||||||
|
width: 80%;
|
||||||
|
height: 100%;
|
||||||
|
background: #f68e1d;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<CheckoutBtn @showShoppingCart="handleShowShoppingCart" @handleCheckoutBtn="handleShowCheckoutCart" />
|
||||||
|
<nut-action-sheet v-model:visible="show">
|
||||||
|
<div class="flex flex-col pb-safe max-h-[60vh] min-h-[60vh]">
|
||||||
|
<div class="bg-[#F5F5F5] px-[30rpx] py-[18rpx] flex items-center">
|
||||||
|
<span class="text-[#666666] text-[30rpx] font-400">已选菜品</span>
|
||||||
|
<div class="text-[#333] font-400 text-[30rpx]">
|
||||||
|
(含运费
|
||||||
|
<span class="text-[#F03B25] text-[30rpx] font-400">¥{{ shippingFee }}</span>
|
||||||
|
打包费 ¥<span class="text-[#F03B25] text-[30rpx] font-400">{{ packingFee }}</span>)
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center ml-auto">
|
||||||
|
<Trash2 :stroke-width="1.5" class="w-[32rpx] h-[32rpx] text-[#ccc]"/>
|
||||||
|
<span class="text-[#666] font-400 text-[32rpx]" @click="handleClearCart">清空</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Carte :carte="shoppingCartList" />
|
||||||
|
<div class="bg-white px-[30rpx] pb-[16rpx]">
|
||||||
|
<CheckoutBtn />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nut-action-sheet>
|
||||||
|
<nut-action-sheet v-model:visible="showCheckoutCart">
|
||||||
|
<div class="flex flex-col pb-safe max-h-[80vh] min-h-[60vh]">
|
||||||
|
<div class="flex items-center w-full px-[30rpx] py-[30rpx] bg-[#F5F5F5]" @click="handleShowChooseLocation">
|
||||||
|
<img src="/images/checkout/location.png" alt="location" class="w-[92rpx] h-[92rpx]">
|
||||||
|
|
||||||
|
<div class="flex flex-col ml-[20rpx] flex-auto">
|
||||||
|
<p class="text-[36rpx] font-600">{{ defaultAddr?.fullAddress }}</p>
|
||||||
|
<div class="flex items-center text-[32rpx] text-[#333] mt-[14rpx]">
|
||||||
|
<span class="mr-[20rpx]">{{ defaultAddr?.name }}</span>
|
||||||
|
<span>{{ defaultAddr?.phone }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ChevronRight :stroke-width="1.5" class="w-[60rpx] h-[60rpx] ml-auto"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Carte :carte="shoppingCartList" class="px-[30rpx]"/>
|
||||||
|
<div class="mx-[30rpx] border-b-dashed border-b-[#D8D8D8] border-b-[2rpx] mb-[40rpx] mt-[20rpx]"></div>
|
||||||
|
<div class="flex flex-col items-center px-[30rpx]">
|
||||||
|
<div class="flex items-center justify-between w-full">
|
||||||
|
<div class="text-[#3d3d3d] text-[30rpx] font-400">打包费</div>
|
||||||
|
<div class="text-[#F03B25] text-[30rpx] font-400">¥{{ packingFee }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between w-full mt-[20rpx] mb-[40rpx]">
|
||||||
|
<div class="text-[#3d3d3d] text-[30rpx] font-400">运费</div>
|
||||||
|
<div class="text-[#F03B25] text-[30rpx] font-400">¥{{ shippingFee }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-[30rpx] pb-[16rpx]">
|
||||||
|
<CheckoutBtn @handleCheckoutBtn="toCheckout"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nut-action-sheet>
|
||||||
|
<ChooseLocation v-model:show="showChooseLocation" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { packingFee, shippingFee } from "@/composables/useRestaurant";
|
||||||
|
import { Trash2, ChevronRight } from "lucide-vue-next";
|
||||||
|
import CheckoutBtn from "./checkout-btn.vue";
|
||||||
|
import { useShoppingCartStore } from "@/store/shoppingCart";
|
||||||
|
import Carte from "./carte.vue";
|
||||||
|
import { useUserStore } from "@/store/user";
|
||||||
|
import ChooseLocation from "@/components/checkout/chooseLocation.vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { CartTypeEnum } from "@/types/cart";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const { recvAddrList } = storeToRefs(userStore);
|
||||||
|
|
||||||
|
const defaultAddr = computed(() => {
|
||||||
|
return recvAddrList.value.find((item:any) => item.isDefault);
|
||||||
|
});
|
||||||
|
|
||||||
|
const shoppingCartStore = useShoppingCartStore();
|
||||||
|
const shoppingCartList = computed(() => {
|
||||||
|
return shoppingCartStore.getShoppingCartByRestaurant;
|
||||||
|
});
|
||||||
|
|
||||||
|
const show = ref(false);
|
||||||
|
const showCheckoutCart = ref(false);
|
||||||
|
const handleShowShoppingCart = () => {
|
||||||
|
show.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShowCheckoutCart = () => {
|
||||||
|
showCheckoutCart.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const showChooseLocation = ref(false);
|
||||||
|
const handleShowChooseLocation = () => {
|
||||||
|
showChooseLocation.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCheckout = () => {
|
||||||
|
router.push({ path: "/checkout/payment", query: { type: CartTypeEnum.Restaurant } });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClearCart = () => {
|
||||||
|
shoppingCartStore.clearShoppingCartByType(CartTypeEnum.Restaurant);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<template>
|
||||||
|
<ul class="px-[30rpx] bg-[#f5f5f5] flex-auto w-full min-h-0 overflow-auto pb-[20rpx]">
|
||||||
|
<li class="p-[20rpx] rounded-[20rpx] bg-white w-full mt-[30rpx]" v-for="(item, index) in shoppingCartList" :key="index">
|
||||||
|
<div class="flex">
|
||||||
|
<img :src="item.cover" alt="cover" class="w-[192rpx] h-[192rpx] rounded-[20rpx]" />
|
||||||
|
<div class="flex flex-col ml-[16rpx] justify-between">
|
||||||
|
<div class="text-[40rpx] font-500">{{ item.name }}</div>
|
||||||
|
<div class="text-[30rpx] text-[#666] font-400 mt-[10rpx]">{{ item.desc }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between items-center mt-[30rpx]">
|
||||||
|
<div class="text-[32rpx] text-[#333] font-400">产品单价</div>
|
||||||
|
<nut-price :price="item.price" size="normal" class="text-[36rpx] font-500" />
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between items-center mt-[22rpx]">
|
||||||
|
<div class="text-[32rpx] text-[#333] font-400">购买数量</div>
|
||||||
|
<nut-input-number v-model="item.count" readonly :min="0" @overlimit="(event, type) => handleOverLimit(event, type, item)"/>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="flex pl-[24rpx] py-[16rpx] pr-[30rpx] items-center justify-between">
|
||||||
|
<nut-price :price="totalPrice" size="large" class="font-500" />
|
||||||
|
<div class="w-[416rpx] h-[100rpx] rounded-[20rpx] bg-[#28BEBB] text-white text-[44rpx] font-600 flex items-center justify-center" @click="toPayment">立即支付</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useShoppingCartStore } from "@/store/shoppingCart";
|
||||||
|
import { CartTypeEnum } from "@/types/cart";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const shoppingCartStore = useShoppingCartStore();
|
||||||
|
const shoppingCartList = ref(shoppingCartStore.getShoppingCartByMall);
|
||||||
|
|
||||||
|
const totalPrice = computed(() => {
|
||||||
|
return shoppingCartList.value.reduce((acc, item) => acc + item.price * item.count, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const toPayment = () => {
|
||||||
|
router.push({ path: "/checkout/payment", query: { type: CartTypeEnum.Mall } });
|
||||||
|
};
|
||||||
|
const handleOverLimit = (_event:any,type:string,item:any) => {
|
||||||
|
if(type === "reduce"){
|
||||||
|
shoppingCartStore.removeShoppingCart(item.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.nut-input-number) {
|
||||||
|
--nut-inputnumber-height: 32px;
|
||||||
|
--nut-inputnumber-input-margin: 0 2px;
|
||||||
|
--nut-inputnumber-input-border-radius: 0;
|
||||||
|
|
||||||
|
& .nut-input-number__icon {
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
& :nth-child(1) {
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& :nth-child(3) {
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<template>
|
||||||
|
<nut-action-sheet v-model:visible="innerShow" class="share-action">
|
||||||
|
<div class="flex flex-col relative pt-[20rpx] px-[20rpx] pb-[42rpx] bg-gradient-to-b from-[#28BEBB] to-[#28BEBB00] rounded-[40rpx_40rpx_0_0]">
|
||||||
|
<img src="/images/product/share-title.png" alt="share-title" class="w-[276rpx] h-[90rpx] absolute top-[-10%] left-[36rpx]" />
|
||||||
|
<div class="rounded-full bg-white w-[60rpx] h-[60rpx] flex items-center justify-center self-end" @click="handleClose">
|
||||||
|
<X />
|
||||||
|
</div>
|
||||||
|
<div class="m-[34rpx] flex items-center">
|
||||||
|
<img src="/images/product/share-wx.png" alt="share-qrcode" class="w-[320rpx] h-[284rpx]" />
|
||||||
|
<img src="/images/product/share-friend.png" alt="share-friend" class="w-[320rpx] h-[284rpx]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nut-action-sheet>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { X } from "lucide-vue-next";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits(["update:show"]);
|
||||||
|
|
||||||
|
const innerShow = computed({
|
||||||
|
get() {
|
||||||
|
return props.show;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
emits("update:show", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
emits("update:show", false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
export interface SvgIconProps {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<SvgIconProps>()
|
||||||
|
|
||||||
|
const styles = useCssModule()
|
||||||
|
const attrs = useAttrs()
|
||||||
|
|
||||||
|
const iconName = computed(() => `#icon-${props.name}`);
|
||||||
|
const svgClass = computed(() => {
|
||||||
|
const className = [styles['svg-icon']]
|
||||||
|
if (props.name) className.push(`icon-${props.name}`)
|
||||||
|
return className
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg :class="svgClass" v-bind="attrs">
|
||||||
|
<use :xlink:href="iconName"></use>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style module>
|
||||||
|
.svg-icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
fill: currentColor;
|
||||||
|
vertical-align: middle;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import SvgIcon from './SvgIcon.vue'
|
||||||
|
import type {SvgIconProps} from './SvgIcon.vue'
|
||||||
|
|
||||||
|
export {
|
||||||
|
SvgIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
export type {
|
||||||
|
SvgIconProps
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<nut-tabbar v-model="activeIndex" @tab-switch="tabSwitch" class="">
|
||||||
|
<nut-tabbar-item v-for="(item,index) in menus" :key="index" :to="`${item.href}`">
|
||||||
|
<template #icon="props">
|
||||||
|
<div class="text-[36rpx] font-500 pt-[36rpx] mt-[8rpx]" :class="props.active ? 'active-bg w-[104rpx] h-[86rpx] text-[40rpx]':''">{{ item.name }}</div>
|
||||||
|
</template>
|
||||||
|
</nut-tabbar-item>
|
||||||
|
</nut-tabbar>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const activeIndex = ref(0);
|
||||||
|
|
||||||
|
const menus = [{name:'首页',href:'/home'},{name:'健康',href:"/medical"},{name:'商城',href:'/shop'},{name:'我的',href:'/mine'}]
|
||||||
|
// const routeQuery = Object.entries(route.query).map(([key, value]) => `${key}=${value}`).join("&");
|
||||||
|
|
||||||
|
const tabSwitch = (item: Record<string, unknown>, index: number) => {
|
||||||
|
console.log(item, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useMatchPath = () => {
|
||||||
|
const path = route.path;
|
||||||
|
activeIndex.value = menus.findIndex(item => item.href === path)
|
||||||
|
}
|
||||||
|
useMatchPath();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.active-bg{
|
||||||
|
background-image: url("/images/tabbar/menu-active.png");
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
:deep(.nut-badge){
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:root{
|
||||||
|
--nut-tabbar-border-bottom:0px solid;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { getRequest } from "@/api/customFetch";
|
||||||
|
import { getLocationByReverseGeography } from "@/api/interfaceDocument";
|
||||||
|
import { mapKey } from "@/utils/useMap";
|
||||||
|
import { useUserStore } from "@/store/user";
|
||||||
|
import { Address } from "@/types/tdt";
|
||||||
|
|
||||||
|
export const useLocationName = (longitude: string, latitude: string) => {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
userStore.setCoordinate(longitude, latitude);
|
||||||
|
userStore.setDeviceCoordinate(longitude, latitude);
|
||||||
|
getRequest(getLocationByReverseGeography(), {
|
||||||
|
postStr: encodeURIComponent(JSON.stringify({ lon: longitude, lat: latitude, ver: 1 })),
|
||||||
|
type: "geocode",
|
||||||
|
tk: mapKey,
|
||||||
|
}).then((resp) => {
|
||||||
|
let _result = resp.result as {
|
||||||
|
addressComponent:Address;
|
||||||
|
};
|
||||||
|
|
||||||
|
const address = _result.addressComponent.town + _result.addressComponent.road;
|
||||||
|
userStore.setAddress(address);
|
||||||
|
userStore.setDeviceAddress({ ..._result.addressComponent });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { getRequest } from "@/api/customFetch";
|
||||||
|
import { getCourseDetail, getLessonCatalog, getLessonCategory, getLessonList } from "@/api/interfaceDocument";
|
||||||
|
|
||||||
|
export const useGetLessonCategory = () => {
|
||||||
|
const lessonCategory = ref<any[]>([]);
|
||||||
|
getRequest(getLessonCategory()).then(resp => {
|
||||||
|
if(resp.code === 200){
|
||||||
|
lessonCategory.value = (resp.result as {categories:any[]}).categories;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { lessonCategory }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetLessonList = () => {
|
||||||
|
const lessonList = ref<any[]>([]);
|
||||||
|
getRequest(getLessonList()).then(resp => {
|
||||||
|
if(resp.code === 200){
|
||||||
|
lessonList.value = (resp.result as {items:any[]}).items;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { lessonList }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetCourseDetail = () => {
|
||||||
|
const courseDetail = ref<any>({});
|
||||||
|
getRequest(getCourseDetail()).then(resp => {
|
||||||
|
if(resp.code === 200){
|
||||||
|
courseDetail.value = resp.result;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { courseDetail }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetCourseCatalog = () => {
|
||||||
|
const courseCatalog = ref<any[]>([]);
|
||||||
|
getRequest(getLessonCatalog()).then(resp => {
|
||||||
|
if(resp.code === 200){
|
||||||
|
courseCatalog.value = (resp.result as {chapters:any[]}).chapters;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { courseCatalog }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { getRequest } from "@/api/customFetch";
|
||||||
|
import { getServiceDetail } from "@/api/interfaceDocument";
|
||||||
|
|
||||||
|
export const useGetServiceDetail = () => {
|
||||||
|
const serviceDetail = ref<any>(null);
|
||||||
|
getRequest(getServiceDetail()).then(res => {
|
||||||
|
serviceDetail.value = res.result;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { serviceDetail };
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { getHousekeepingCleaningList,getHousekeepingCleaningDetail } from "@/api/interfaceDocument";
|
||||||
|
import { getRequest } from "@/api/customFetch";
|
||||||
|
|
||||||
|
export const useGetHousekeepingCleaningList = () => {
|
||||||
|
const cleaningList = ref<any[]>([]);
|
||||||
|
getRequest(getHousekeepingCleaningList()).then((res) => {
|
||||||
|
cleaningList.value = res.result as any[]
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
cleaningList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetHousekeepingCleaningDetail = () => {
|
||||||
|
const cleaningDetail = ref<any>({});
|
||||||
|
getRequest(getHousekeepingCleaningDetail()).then((res) => {
|
||||||
|
cleaningDetail.value = res.result as any
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
cleaningDetail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { getRequest } from "@/api/customFetch"
|
||||||
|
import { getNotifyList } from "@/api/interfaceDocument"
|
||||||
|
|
||||||
|
|
||||||
|
export const useGetNoticeList = () => {
|
||||||
|
const noticeList = ref<any[]>([])
|
||||||
|
getRequest(getNotifyList()).then(resp => {
|
||||||
|
if(resp.code === 200){
|
||||||
|
noticeList.value = (resp.result as {list:any[]}).list
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { noticeList }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { getNursingHomeList, getNursingDetail } from "@/api/interfaceDocument";
|
||||||
|
import { getRequest } from "@/api/customFetch";
|
||||||
|
|
||||||
|
export const useNursingHomeList = () => {
|
||||||
|
const nursingHomeList = ref<any[]>([]);
|
||||||
|
getRequest(getNursingHomeList()).then(resp => {
|
||||||
|
if(resp.code === 200){
|
||||||
|
nursingHomeList.value = (resp.result as { list: any[] }).list;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {nursingHomeList}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNursingDetail = () => {
|
||||||
|
const nursingDetail = ref<any>({});
|
||||||
|
getRequest(getNursingDetail()).then(resp => {
|
||||||
|
if(resp.code === 200){
|
||||||
|
nursingDetail.value = (resp.result as { data: any }).data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { nursingDetail };
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { getRequest } from "@/api/customFetch";
|
||||||
|
import { getRestaurantFoodDetail, getRestaurantFoodList, getRestaurantFoodSet } from "@/api/interfaceDocument";
|
||||||
|
|
||||||
|
export const foodList = ref<any[]>([]);
|
||||||
|
export const packingFee = ref(0);
|
||||||
|
export const shippingFee = ref(0);
|
||||||
|
export const useRestaurantFoodList = () => {
|
||||||
|
|
||||||
|
getRequest(getRestaurantFoodList()).then((resp) => {
|
||||||
|
if (resp.code === 200) {
|
||||||
|
foodList.value = (resp.result as { items: any[] }).items;
|
||||||
|
packingFee.value = (resp.result as { packingFee: number }).packingFee;
|
||||||
|
shippingFee.value = (resp.result as { shippingFee: number }).shippingFee;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const foodSetList = ref<any[]>([]);
|
||||||
|
export const useRestaurantFoodSet = () => {
|
||||||
|
getRequest(getRestaurantFoodSet()).then((resp) => {
|
||||||
|
if (resp.code === 200) {
|
||||||
|
foodSetList.value = (resp.result as { items: any[] }).items;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const useRestaurantFoodDetail = () => {
|
||||||
|
const foodDetail = ref<any>({});
|
||||||
|
|
||||||
|
getRequest(getRestaurantFoodDetail()).then((resp) => {
|
||||||
|
if (resp.code === 200) {
|
||||||
|
foodDetail.value = resp.result;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {foodDetail}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { getRequest } from "@/api/customFetch";
|
||||||
|
import { getTravelList } from "@/api/interfaceDocument";
|
||||||
|
|
||||||
|
export const useTravelList = () => {
|
||||||
|
const travelList = ref<any[]>([]);
|
||||||
|
const travelCategory = ref<any[]>([]);
|
||||||
|
|
||||||
|
getRequest(getTravelList()).then((resp) => {
|
||||||
|
if (resp.code === 200) {
|
||||||
|
travelList.value = (resp.result as { data:{products: any[]} }).data.products;
|
||||||
|
travelCategory.value = (resp.result as {data: {categories: any[]} }).data.categories.map((item,index) => ({title:item,paneKey:index.toString()}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { travelList,travelCategory };
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { getUserAddressList } from "@/api/interfaceDocument"
|
||||||
|
import { getRequest } from "@/api/customFetch"
|
||||||
|
import { useUserStore } from "@/store/user"
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
export const address = ref<any[]>([])
|
||||||
|
export const defaultAddress = ref(1);
|
||||||
|
|
||||||
|
export const useMatchDefault = () => {
|
||||||
|
const matchAddress = address.value.find(item => item.isDefault);
|
||||||
|
if(matchAddress){
|
||||||
|
defaultAddress.value = matchAddress.id
|
||||||
|
}else{
|
||||||
|
defaultAddress.value = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetUserAddressList = () => {
|
||||||
|
getRequest(getUserAddressList()).then(resp => {
|
||||||
|
if(resp.code === 200){
|
||||||
|
address.value = (resp.result as {list:any[]}).list
|
||||||
|
useMatchDefault()
|
||||||
|
userStore.setRecvAddrList(address.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { createApp } from 'vue'
|
||||||
|
import '@unocss/reset/tailwind-compat.css'
|
||||||
|
import './style.css'
|
||||||
|
import 'uno.css';
|
||||||
|
import App from './App.vue'
|
||||||
|
// Pinia 持久化
|
||||||
|
import store from '@/store/index'
|
||||||
|
//导入路由
|
||||||
|
import router from '@/router/index'
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
// 注册已经加上了持久化的pinia
|
||||||
|
app.use(store).use(router)
|
||||||
|
|
||||||
|
app.mount('#app')
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
|
import { publicRoutes } from "./publicRoutes";
|
||||||
|
import { privateRoutes } from "./privateRoutes";
|
||||||
|
function getRoutes() {
|
||||||
|
const routes = [ // 私有路由,请在这里添加
|
||||||
|
...privateRoutes,
|
||||||
|
|
||||||
|
// 公共路由
|
||||||
|
...publicRoutes,
|
||||||
|
];
|
||||||
|
/**
|
||||||
|
* 如果要对 routes 做一些处理,请在这里修改
|
||||||
|
*/
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(),
|
||||||
|
routes: getRoutes(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// 全局前置守卫,这边可以对身份进行验证
|
||||||
|
router.beforeEach((to, _from, next) => {
|
||||||
|
let userRole = "admin";
|
||||||
|
// 如果目标路由没有角色限制
|
||||||
|
if (!to.meta.role) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
// 判断当前用户角色是否在目标路由的允许角色列表中
|
||||||
|
if ((to.meta.role as string[]).includes(userRole)) {
|
||||||
|
// 如果角色匹配,允许进入目标路由
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
// 如果角色不匹配,跳转到 unauthorized 页面
|
||||||
|
next({ path: "/unauthorized" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听路由变化,动态设置网页标题
|
||||||
|
router.afterEach((to) => {
|
||||||
|
if (to.meta.title) {
|
||||||
|
document.title = to.meta.title as string;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { ComponentInternalInstance, ref } from 'vue'
|
||||||
|
|
||||||
|
export const excludes = ref<string[]>([])
|
||||||
|
|
||||||
|
export function removeKeepAliveCache(instance: ComponentInternalInstance) {
|
||||||
|
if (!excludes.value.includes(instance.type.name!)) {
|
||||||
|
excludes.value.push(instance.type.name!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetKeepAliveCache(instance: ComponentInternalInstance) {
|
||||||
|
excludes.value = excludes.value.filter((item) => item !== instance.type.name)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { RouteRecordRaw } from "vue-router";
|
||||||
|
|
||||||
|
export const privateRoutes:RouteRecordRaw[] = [];
|
||||||
|
|
@ -0,0 +1,317 @@
|
||||||
|
import { RouteRecordRaw } from "vue-router";
|
||||||
|
|
||||||
|
export const publicRoutes:RouteRecordRaw[] = [
|
||||||
|
{
|
||||||
|
path: "/home",
|
||||||
|
name: "home",
|
||||||
|
meta: {
|
||||||
|
title: "康乐云家",
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
default: () => import("../views/home/index.vue"),
|
||||||
|
tabbar: () => import("../components/tabbar/index.vue")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/location/map",
|
||||||
|
name: "map",
|
||||||
|
meta: {
|
||||||
|
title: "新增地址",
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/location/map.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/location/administrative",
|
||||||
|
name: "administrative",
|
||||||
|
meta: {
|
||||||
|
title: "选择城市",
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/location/administrative.vue")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/medical",
|
||||||
|
name: "medical",
|
||||||
|
meta: {
|
||||||
|
title: "康乐云家",
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
default: () => import("../views/medical/index.vue"),
|
||||||
|
tabbar: () => import("../components/tabbar/index.vue")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/shop",
|
||||||
|
name: "shop",
|
||||||
|
meta: {
|
||||||
|
title: "康乐云家",
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
default: () => import("../views/shop/index.vue"),
|
||||||
|
tabbar: () => import("../components/tabbar/index.vue")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/shop/product",
|
||||||
|
name: "product",
|
||||||
|
meta: {
|
||||||
|
title: "商品详情",
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/shop/productInfo.vue"),tabbar: () => import("../components/back-button/index.vue")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/checkout",
|
||||||
|
name: "checkout",
|
||||||
|
meta: {
|
||||||
|
title: "确认订单",
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/checkout/index.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/checkout/payment",
|
||||||
|
name: "payment",
|
||||||
|
meta: {
|
||||||
|
title: "支付成功",
|
||||||
|
},
|
||||||
|
component: () => import("../views/checkout/payment.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:"/checkout/health-care",
|
||||||
|
name:"health-care-checkout",
|
||||||
|
meta:{
|
||||||
|
title:"确认订单"
|
||||||
|
},
|
||||||
|
components:{default:() => import("../views/checkout/healthCare.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:"/housekeeping/order/:id",
|
||||||
|
name:"housekeeping-checkout",
|
||||||
|
meta:{
|
||||||
|
title:"确认订单"
|
||||||
|
},
|
||||||
|
components:{default:() => import("../views/housekeeping/order.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: "/mine",
|
||||||
|
name: "mine",
|
||||||
|
meta: {
|
||||||
|
title: "康乐云家",
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
default: () => import("../views/mine/index.vue"),
|
||||||
|
tabbar: () => import("../components/tabbar/index.vue")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/mine/address',
|
||||||
|
name:'my-address',
|
||||||
|
meta:{
|
||||||
|
title:'收获地址管理'
|
||||||
|
},
|
||||||
|
component: () => import("../views/mine/addressManagement.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/mine/add/address',
|
||||||
|
name:'add-address',
|
||||||
|
meta:{
|
||||||
|
title:'收获地址管理'
|
||||||
|
},
|
||||||
|
component: () => import("../views/mine/addAddress.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/mine/add/paramedic',
|
||||||
|
name:'add-paramedic',
|
||||||
|
meta:{
|
||||||
|
title:'新增被护理人'
|
||||||
|
},
|
||||||
|
component: () => import("../views/mine/addParamedic.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/mine/notice',
|
||||||
|
name:'notice',
|
||||||
|
meta:{
|
||||||
|
title:'消息中心'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/mine/notice.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/mine/orders',
|
||||||
|
name:"mine-orders",
|
||||||
|
meta:{
|
||||||
|
title:'我的订单'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/mine/orders.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/mine/user-info',
|
||||||
|
name:'mine-user-info',
|
||||||
|
meta:{
|
||||||
|
title:'个人资料'
|
||||||
|
},
|
||||||
|
component: () => import("../views/mine/userInfo.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/restaurant',
|
||||||
|
name:'restaurant',
|
||||||
|
meta:{
|
||||||
|
title:'社区点餐'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/restaurant/index.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:"/restaurant/detail/:id",
|
||||||
|
name:"restaurant-detail",
|
||||||
|
meta:{
|
||||||
|
title:"商品详情"
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/restaurant/detail.vue"),backButton:() => import("../components/back-button/index.vue")}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/courses',
|
||||||
|
name:'courses',
|
||||||
|
meta:{
|
||||||
|
title:'课程学习'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/courses/index.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/courses/detail/:id',
|
||||||
|
name:'courses-detail',
|
||||||
|
meta:{
|
||||||
|
title:'课程详情'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/courses/detail.vue"),backButton:() => import("../components/back-button/index.vue")}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/courses/cart/:id',
|
||||||
|
name:'courses-cart',
|
||||||
|
meta:{
|
||||||
|
title:'购买课程'
|
||||||
|
},
|
||||||
|
component: () => import("../views/courses/courseCart.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/travel',
|
||||||
|
name:'travel',
|
||||||
|
meta:{
|
||||||
|
title:'乐享夕阳行'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/travel/index.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/health-care',
|
||||||
|
name:'health-care',
|
||||||
|
meta:{
|
||||||
|
title:'康养护理'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/healthCare/index.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/health-care/order/:id',
|
||||||
|
name:'health-care-order',
|
||||||
|
meta:{
|
||||||
|
title:'预约'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/healthCare/order.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/jinze',
|
||||||
|
name:'jinze',
|
||||||
|
meta:{
|
||||||
|
title:'锦泽安康'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/jinze/index.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/jinze/detail/:id',
|
||||||
|
name:'jinze-detail',
|
||||||
|
meta:{
|
||||||
|
title:'养老院详情'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/jinze/detail.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/jinze/images/:id',
|
||||||
|
name:'jinze-images',
|
||||||
|
meta:{
|
||||||
|
title:'泰康之家·锦绣府'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/jinze/images.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/jinze/patient-situation',
|
||||||
|
name:'jinze-patient-situation',
|
||||||
|
meta:{
|
||||||
|
title:'情况描述'
|
||||||
|
},
|
||||||
|
component: () => import("../views/jinze/patientSituation.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/home/address',
|
||||||
|
name:'current-address',
|
||||||
|
meta:{
|
||||||
|
title:'选择定位'
|
||||||
|
},
|
||||||
|
component: () => import("../views/home/currentLocation.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/housekeeping',
|
||||||
|
name:'housekeeping',
|
||||||
|
meta:{
|
||||||
|
title:'预约家政'
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/housekeeping/index.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
props:{
|
||||||
|
backButton:{bottom:"15vh"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:"/housekeeping/detail/:id",
|
||||||
|
name:"housekeeping-detail",
|
||||||
|
meta:{
|
||||||
|
title:"家政详情"
|
||||||
|
},
|
||||||
|
components: {default:() => import("../views/housekeeping/detail.vue"),backButton:() => import("../components/back-button/index.vue")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/unauthorized",
|
||||||
|
name: "unauthorized",
|
||||||
|
meta: {
|
||||||
|
title: "unauthorized",
|
||||||
|
},
|
||||||
|
component: () => import("../views/unauthorized.vue"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// pinia数据持久化存储
|
||||||
|
import { createPinia } from 'pinia'
|
||||||
|
import { createPersistedState } from 'pinia-plugin-persistedstate'
|
||||||
|
import { SelfStorage } from './secureStore'
|
||||||
|
|
||||||
|
// 第一个参数是应用程序中 store 的唯一 id
|
||||||
|
const store = createPinia()
|
||||||
|
store.use(
|
||||||
|
createPersistedState({
|
||||||
|
storage: SelfStorage
|
||||||
|
})
|
||||||
|
)
|
||||||
|
export default store
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue