add:管理端

This commit is contained in:
2025-11-26 10:05:45 +08:00
parent 38bfd8eae1
commit d375e08dde
129 changed files with 28564 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
*.local
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+107
View File
@@ -0,0 +1,107 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
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 onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onError: typeof import('@dcloudio/uni-app')['onError']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onHide: typeof import('@dcloudio/uni-app')['onHide']
const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch']
const onLoad: typeof import('@dcloudio/uni-app')['onLoad']
const onMounted: typeof import('vue')['onMounted']
const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']
const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']
const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']
const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']
const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']
const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound']
const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll']
const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh']
const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom']
const onReady: typeof import('@dcloudio/uni-app')['onReady']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onResize: typeof import('@dcloudio/uni-app')['onResize']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage']
const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline']
const onShow: typeof import('@dcloudio/uni-app')['onShow']
const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap']
const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange']
const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection']
const onUnload: typeof import('@dcloudio/uni-app')['onUnload']
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 useModel: typeof import('vue')['useModel']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const useToast: typeof import('nutui-uniapp/composables')['useToast']
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, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}
+39
View File
@@ -0,0 +1,39 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by vite-plugin-uni-components
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
Carebox: typeof import('./src/components/carebox/index.vue')['default']
CarNoSelecter: typeof import('./src/components/carNoSelecter/index.vue')['default']
Gender: typeof import('./src/components/gender/index.vue')['default']
HasListCareBox: typeof import('./src/components/hasListCareBox/index.vue')['default']
HeaderBox: typeof import('./src/components/headerBox/index.vue')['default']
Largebox: typeof import('./src/components/largebox/index.vue')['default']
NutButton: typeof import('nutui-uniapp/components/button/button.vue')['default']
NutCol: typeof import('nutui-uniapp/components/col/col.vue')['default']
NutForm: typeof import('nutui-uniapp/components/form/form.vue')['default']
NutFormItem: typeof import('nutui-uniapp/components/formitem/formitem.vue')['default']
NutInput: typeof import('nutui-uniapp/components/input/input.vue')['default']
NutNavbar: typeof import('nutui-uniapp/components/navbar/navbar.vue')['default']
NutPicker: typeof import('nutui-uniapp/components/picker/picker.vue')['default']
NutPopup: typeof import('nutui-uniapp/components/popup/popup.vue')['default']
NutRow: typeof import('nutui-uniapp/components/row/row.vue')['default']
NutSafeArea: typeof import('nutui-uniapp/components/safearea/safearea.vue')['default']
NutTabPane: typeof import('nutui-uniapp/components/tabpane/tabpane.vue')['default']
NutTabs: typeof import('nutui-uniapp/components/tabs/tabs.vue')['default']
NutTextarea: typeof import('nutui-uniapp/components/textarea/textarea.vue')['default']
OrderItem: typeof import('./src/components/orderItem/index.vue')['default']
Petheaderchoose: typeof import('./src/components/petheaderchoose/index.vue')['default']
PetSmallBox: typeof import('./src/components/petSmallBox/index.vue')['default']
PetSwiper: typeof import('./src/components/petSwiper/petSwiper.vue')['default']
Selecter: typeof import('./src/components/selecter/index.vue')['default']
Timepopup: typeof import('./src/components/timepopup/index.vue')['default']
TimeSlotItem: typeof import('./src/components/timeSlotItem/index.vue')['default']
}
}
+10
View File
@@ -0,0 +1,10 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import pluginVue from "eslint-plugin-vue";
export default [
{languageOptions: { globals: globals.browser }},
pluginJs.configs.recommended,
...pluginVue.configs["flat/essential"],
];
+20
View File
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
+12695
View File
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev:app": "uni -p app --mode development",
"dev:app-android": "uni -p app-android --mode development",
"dev:app-ios": "uni -p app-ios --mode development",
"dev:custom": "uni -p --mode development",
"dev:h5": "uni --mode development",
"dev:h5:ssr": "uni --ssr --mode development",
"dev:mp-alipay": "uni -p mp-alipay --mode development",
"dev:mp-baidu": "uni -p mp-baidu --mode development",
"dev:mp-jd": "uni -p mp-jd --mode development",
"dev:mp-kuaishou": "uni -p mp-kuaishou --mode development",
"dev:mp-lark": "uni -p mp-lark --mode development",
"dev:mp-qq": "uni -p mp-qq --mode development",
"dev:mp-toutiao": "uni -p mp-toutiao --mode development",
"dev:mp-weixin": "uni -p mp-weixin --mode development",
"dev:mp-xhs": "uni -p mp-xhs --mode development",
"dev:quickapp-webview": "uni -p quickapp-webview --mode development",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei --mode development",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union --mode development",
"build:app": "uni build -p app --mode production",
"build:app-android": "uni build -p app-android --mode production",
"build:app-ios": "uni build -p app-ios --mode production",
"build:custom": "uni build -p --mode production",
"build:h5": "uni build --mode production",
"build:h5:ssr": "uni build --ssr --mode production",
"build:mp-alipay": "uni build -p mp-alipay --mode production",
"build:mp-baidu": "uni build -p mp-baidu --mode production",
"build:mp-jd": "uni build -p mp-jd --mode production",
"build:mp-kuaishou": "uni build -p mp-kuaishou --mode production",
"build:mp-lark": "uni build -p mp-lark --mode production",
"build:mp-qq": "uni build -p mp-qq --mode production",
"build:mp-toutiao": "uni build -p mp-toutiao --mode production",
"build:mp-weixin": "uni build -p mp-weixin --mode production",
"build:mp-xhs": "uni build -p mp-xhs --mode production",
"build:quickapp-webview": "uni build -p quickapp-webview --mode production",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei --mode production",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union --mode production",
"lint": "eslint --ext .js,.vue,.ts src --fix"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4000820240401001",
"@dcloudio/uni-app-plus": "3.0.0-4000820240401001",
"@dcloudio/uni-components": "3.0.0-4000820240401001",
"@dcloudio/uni-h5": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-alipay": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-baidu": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-jd": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-lark": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-qq": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-toutiao": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-weixin": "3.0.0-4000820240401001",
"@dcloudio/uni-mp-xhs": "3.0.0-4000820240401001",
"@dcloudio/uni-quickapp-webview": "3.0.0-4000820240401001",
"moment": "^2.30.1",
"nutui-uniapp": "^1.7.7",
"pinia": "2.0.35",
"vue": "^3.4.21",
"vue-i18n": "^9.12.0"
},
"devDependencies": {
"@dcloudio/types": "^3.4.8",
"@dcloudio/uni-automator": "3.0.0-4000820240401001",
"@dcloudio/uni-cli-shared": "3.0.0-4000820240401001",
"@dcloudio/uni-stacktracey": "3.0.0-4000820240401001",
"@dcloudio/vite-plugin-uni": "3.0.0-4000820240401001",
"@eslint/js": "^9.0.0",
"@uni-helper/vite-plugin-uni-components": "^0.0.9",
"@vue/runtime-core": "^3.4.21",
"eslint": "^9.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.24.1",
"globals": "^15.0.0",
"prettier": "^3.2.5",
"sass": "^1.75.0",
"vite": "4.3.5"
}
}
+7150
View File
File diff suppressed because it is too large Load Diff
+25
View File
@@ -0,0 +1,25 @@
{
"setting": {
"es6": true,
"postcss": true,
"minified": true,
"uglifyFileName": false,
"enhance": true,
"packNpmRelationList": [],
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"useCompilerPlugins": false,
"minifyWXML": true
},
"compileType": "miniprogram",
"simulatorPluginLibVersion": {},
"packOptions": {
"ignore": [],
"include": []
},
"appid": "wx047689e2fd64e87e",
"editorSetting": {}
}
+14
View File
@@ -0,0 +1,14 @@
{
"libVersion": "3.8.9",
"projectname": "managePet-mini-program",
"setting": {
"urlCheck": true,
"coverView": true,
"lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false,
"preloadBackgroundData": false,
"autoAudits": false,
"showShadowRootInWxmlPanel": true,
"compileHotReLoad": true
}
}
+10
View File
@@ -0,0 +1,10 @@
/// <reference types='@dcloudio/types' />
import 'vue'
declare module '@vue/runtime-core' {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {
}
}
+25
View File
@@ -0,0 +1,25 @@
<script setup>
import eventBus from './utils/eventBus'
onLaunch(() => {
// 挂载eventbus
wx.eventBus = eventBus
console.log('App Launch')
})
onShow(() => {
console.log('App Show')
})
onHide(() => {
console.log('App Hide')
})
</script>
<style lang="scss">
@import "nutui-uniapp/styles/index.scss";
view {
--nut-navbar-title-font: 34rpx;
--nut-navbar-title-font-weight: 500;
}
</style>
+37
View File
@@ -0,0 +1,37 @@
import request from '@/utils/request';
import requestNew from '../utils/requestNew';
//jwt登录
export function apiLogin(data) {
return requestNew({
url: `/api/franchisee2/api/login`,
method: "post",
data,
})
}
// 登陆
export function getuser(data) {
return request({
url: '/auth/login',
data,
method: "post"
})
}
// 获取用户信息
export function getUserInfo() {
return request({
url: '/auth/getUserInfo',
method: "post"
})
}
// 修改用户信息
export function updateUserInfo(data) {
return request({
url: '/auth/updateUserInfo',
method: "post",
data
})
}
+45
View File
@@ -0,0 +1,45 @@
import request from '@/utils/request';
//地址列表/service/serviceAddrList
export function serviceAddrLists(data) {
return request({
url: `/api/franchisee2/service/serviceAddrList?uid=${data}`,
method: 'post'
});
}
//用户服务地址添加/更新 /api​/franchisee2​/service​/serviceAddOrEdit
export function serviceAddOrEdit(data) {
return request({
url: `/api/franchisee2/service/serviceAddOrEdit`,
method: 'post',
data,
});
}
export function serviceAreaAddrList(data) {
return request({
url: `/service/serviceAreaAddrList`,
method: 'post',
data,
});
}
// /service/serviceCarLocationUpload
export function serviceCarLocationUpload(data){
return request({
url: `/service/serviceCarLocationUpload`,
method: 'post',
data,
});
}
// /service/serviceCarLocationList
export function serviceCarLocationList(data){
return request({
url: `/service/serviceCarLocationList`,
method: 'post',
data,
});
}
+48
View File
@@ -0,0 +1,48 @@
import request from '@/utils/request';
//新增车辆下架信息
export function carAddDownTime(data) {
return request({
url: `/api/franchisee2/car/add/downTime`,
method: 'post',
data
});
}
//护理人员删除关联
export function carDelCarUser(data) {
return request({
url: `/api/franchisee2/car/delCarUser`,
method: 'post',
data
});
}
//删除车辆下架信息
export function carDeleteDownTime(data) {
return request({
url: `/api/franchisee2/car/delete/downTime`,
method: 'post',
data
});
}
//获取当前用户角色下的car列表
export function carList(data) {
return request({
// url: `/api/franchisee2/car/list?uid=${data}`,
url:`/api/franchisee2/order/car?uid=${data}`,
method: 'post'
});
}
//添加护理人员
export function carSaveCarUser(data) {
return request({
url: `/api/franchisee2/car/saveCarUser`,
method: 'post',
data
});
}
+24
View File
@@ -0,0 +1,24 @@
import requestNew from '@/utils/requestNew.js';
//获取洗护宠物详情
export function cleaningPetInfo(id) {
return requestNew({
url: `/api/miniProgram/pet/petInfo?id=${id}`,
method: 'get',
});
}
//获取洗护宠物列表
export function cleaningPetList(uid) {
return requestNew({
url: `/api/miniProgram/users/pet/petList?uid=${uid}`,
method: 'get',
});
}
//根据ID获取总的洗护次数
export function cleaningPetListCount(uid) {
return requestNew({
url: `/api/miniProgram/users/wash/count?uid=${uid}`,
method: 'get',
});
}
+26
View File
@@ -0,0 +1,26 @@
import request from '@/utils/request';
//地址列表
export function getCouponsList() {
return request({
url: `/coupons/getCouponsList`,
method: 'post'
});
}
// /coupons/getUserCouponsList
export function getUserCouponsList(data) {
return request({
url: `/coupons/getUserCouponsList`,
method: 'post',
data
});
}
// /coupons/drawCoupons
export function drawCoupons(data) {
return request({
url: `/coupons/drawCoupons`,
method: 'post',
data
});
}
+37
View File
@@ -0,0 +1,37 @@
import request from '@/utils/request';
// import { requestPort } from '@/utils/requestPort';
//宠物列表
export function getGoodsList(data) {
return request({
url: `/goods/goodsList`,
method: 'post',
data,
});
}
// /order/orderServiceTime
export function orderServiceTime(data) {
return request({
url: `/order/orderServiceTime`,
method: 'post',
data
});
}
// /order/orderCreate
export function orderCreate(data) {
return request({
url: `/order/orderCreate`,
method: 'post',
data
});
}
// /order/orderCreatePreCheck
export function orderCreatePreCheck(data) {
return request({
url: '/order/orderCreatePreCheck',
method: 'post',
data
})
}
+71
View File
@@ -0,0 +1,71 @@
import request from '@/utils/request';
//订单list
export function orderList(data) {
return request({
url: `/api/franchisee2/order/list`,
method: 'post',
data
});
}
//订单修改
export function orderUpdate(data) {
return request({
url: `/api/franchisee2/order/update`,
method: 'post',
data
});
}
//订单取消
export function orderCancel(ids) {
return request({
url: `/api/franchisee2/order/cancel?ids=${ids}`,
method: 'post',
});
}
//车辆派单
export function orderCar(data) {
return request({
url: `/api/franchisee2/car/list?uid=${data}`,
method: 'post'
});
}
//派单
export function orderDispatch(data) {
return request({
url: `/api/franchisee2/order/dispatch`,
method: 'post',
data
});
}
//派单时可以选车辆列表
export function orderDispatchCarList(data) {
return request({
url: `/api/franchisee2/order/dispatch/carList`,
method: 'post',
data
});
}
//车辆排单
export function orderCarList(uid) {
return request({
url: `/api/franchisee2/order/car/list?uid=${uid}`,
method: 'post'
});
}
//详情
export function orderDetail(data) {
return request({
url: `/api/order/orderDetail?orderId=${data}`,
method: 'get',
});
}
+42
View File
@@ -0,0 +1,42 @@
import request from '@/utils/request';
// import { requestPort } from '@/utils/requestPort';
//宠物列表
export function petList(data) {
return request({
url: `/pet/petList`,
method: 'post',
data,
});
}
//宠物信息
export function petInfo(data) {
return request({
url: `/pet/petInfo`,
method: 'post',
data,
});
}
//宠物基础信息列表
export function petTypeList(data) {
return request({
url: `/pet/petTypeList`,
method: 'post',
data,
});
}
//宠物添加/修改
export function petAddOrEdit(data) {
return request({
url: `/pet/petAddOrEdit`,
method: 'post',
data,
});
}
//删除宠物
export function delPet(data) {
return request({
url: `/pet/delPet`,
method: 'post',
data,
});
}
+19
View File
@@ -0,0 +1,19 @@
import request from '@/utils/request';
//banner
export function systemBanners(data) {
return request({
url: `/system/systemBanners`,
method: 'post',
data,
});
}
//系统配置
export function systemConfigInfo(data) {
return request({
url: `/system/systemConfigInfo`,
method: 'post',
data,
});
}
+3
View File
@@ -0,0 +1,3 @@
// 主色调
$primary-color: #FFCD35;
$primary-color-end: #FFDE5E;
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+560
View File
@@ -0,0 +1,560 @@
<template>
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{label + ':'}}</span>
<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
<view class="uni-select" :class="{'uni-select--disabled':disabled}">
<view class="uni-select__input-box" @click="toggleSelector">
<view v-if="current" class="uni-select__input-text">{{textShow}}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
<view key="clear-button" v-if="current && clear && !disabled" @click.stop="clearVal">
<image class="icon" src="../../static/images/delete.png" mode="aspectFill"></image>
</view>
<view key="arrow-button" v-else class="select-icon">
<image v-if="showSelector" class="icon" src="../../static/images/down_arrow.png"
mode="aspectFill"></image>
<image v-else class="icon" src="../../static/images/ringht_arrow.png" mode="aspectFill"></image>
</view>
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" :style="getOffsetByPlacement" v-if="showSelector">
<view :class="placement=='bottom'?'uni-popper__arrow_bottom':'uni-popper__arrow_top'"></view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
<text>{{emptyTips}}</text>
</view>
<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData"
:key="index" @click="change(item)">
<text
:class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "carNoSelecter",
mixins: [uniCloud.mixinDatacom || {}],
props: {
localdata: {
type: Array,
default () {
return []
}
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
emptyTips: {
type: String,
default: '无选项'
},
clear: {
type: Boolean,
default: true
},
defItem: {
type: Number,
default: 0
},
disabled: {
type: Boolean,
default: false
},
format: {
type: String,
default: ''
},
placement: {
type: String,
default: 'bottom'
}
},
data() {
return {
showSelector: false,
current: '',
mixinDatacomResData: [],
apps: [],
channels: [],
cacheKey: "uni-data-select-lastSelectedValue",
};
},
created() {
this.debounceGet = this.debounce(() => {
this.query();
}, 300);
if (this.collection && !this.localdata.length) {
this.debounceGet();
}
},
computed: {
typePlaceholder() {
const text = {
}
const common = this.placeholder
const placeholder = text[this.collection]
return common
},
valueCom() {
// #ifdef VUE3
return this.modelValue;
// #endif
// #ifndef VUE3
return this.value;
// #endif
},
textShow() {
// 长文本显示
let text = this.current;
return text;
},
getOffsetByPlacement() {
switch (this.placement) {
case 'top':
return "bottom:calc(100% + 12px);";
case 'bottom':
return "top:calc(100% + 12px);";
}
}
},
watch: {
localdata: {
immediate: true,
handler(val, old) {
if (Array.isArray(val) && old !== val) {
this.mixinDatacomResData = val
}
}
},
valueCom(val, old) {
this.initDefVal()
},
mixinDatacomResData: {
immediate: true,
handler(val) {
if (val.length) {
this.initDefVal()
}
}
},
},
methods: {
debounce(fn, time = 100) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, time)
}
},
// 执行数据库查询
query() {
this.mixinDatacomEasyGet();
},
// 监听查询条件变更事件
onMixinDatacomPropsChange() {
if (this.collection) {
this.debounceGet();
}
},
initDefVal() {
let defValue = ''
if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
defValue = this.valueCom
} else {
let strogeValue
if (this.collection) {
strogeValue = this.getCache()
}
if (strogeValue || strogeValue === 0) {
defValue = strogeValue
} else {
let defItem = ''
if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
defItem = this.mixinDatacomResData[this.defItem - 1].value
}
defValue = defItem
}
if (defValue || defValue === 0) {
this.emit(defValue)
}
}
const def = this.mixinDatacomResData.find(item => item.value === defValue)
this.current = def ? this.formatItemName(def) : ''
},
/**
* @param {[String, Number]} value
* 判断用户给的 value 是否同时为禁用状态
*/
isDisabled(value) {
let isDisabled = false;
this.mixinDatacomResData.forEach(item => {
if (item.value === value) {
isDisabled = item.disable
}
})
return isDisabled;
},
clearVal() {
this.emit('')
this.current = ''
if (this.collection) {
this.removeCache()
}
},
change(item) {
console.log('1=======',item)
if (!item.disable) {
this.showSelector = false
this.current = this.formatItemName(item)
this.emit(item)
}
},
emit(val) {
this.$emit('input', val)
this.$emit('update:modelValue', val)
this.$emit('change', val)
if (this.collection) {
this.setCache(val);
}
},
toggleSelector() {
if (this.disabled) {
return
}
this.showSelector = !this.showSelector
},
formatItemName(item) {
let {
text,
value,
channel_code
} = item
channel_code = channel_code ? `(${channel_code})` : ''
if (this.format) {
// 格式化输出
let str = "";
str = this.format;
for (let key in item) {
str = str.replace(new RegExp(`{${key}}`, "g"), item[key]);
}
return str;
} else {
console.log('this.collection======', this.collection)
return this.collection.indexOf('app-list') > 0 ?
`${text}(${value})` :
(
text ?
text :
`未命名${channel_code}`
)
}
},
// 获取当前加载的数据
getLoadData() {
return this.mixinDatacomResData;
},
// 获取当前缓存key
getCurrentCacheKey() {
return this.collection;
},
// 获取缓存
getCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
return cacheData[name];
},
// 设置缓存
setCache(value, name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
cacheData[name] = value;
uni.setStorageSync(this.cacheKey, cacheData);
},
// 删除缓存
removeCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
delete cacheData[name];
uni.setStorageSync(this.cacheKey, cacheData);
},
}
}
</script>
<style lang="scss">
$uni-base-color: #6a6a6a !default;
$uni-main-color: #333 !default;
$uni-secondary-color: #909399 !default;
$uni-border-3: #e5e5e5;
/* #ifndef APP-NVUE */
@media screen and (max-width: 700px) {
.hide-on-phone {
display: none;
}
}
/* #endif */
.uni-stat__select {
display: flex;
align-items: center;
// padding: 15px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
width: 650rpx;
flex: 1;
box-sizing: border-box;
}
.uni-stat-box {
background-color:rgba(0, 0, 0, 0); // #fff;
width: 100%;
flex: 1;
// background-color: aqua;
}
.uni-stat__actived {
width: 100%;
flex: 1;
// outline: 1px solid #2979ff;
}
.uni-label-text {
font-size: 16px;
font-weight: bold;
color: $uni-base-color;
margin: auto 0;
margin-right: 5px;
}
.uni-select {
font-size: 16px;
// border: 1px solid $uni-border-3;
box-sizing: border-box;
border-radius: 4px;
padding: 0 5px;
padding-left: 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
user-select: none;
/* #endif */
flex-direction: row;
align-items: center;
// border-bottom: solid 1px $uni-border-3;
width: 100%;
flex: 1;
height: 50px;
&--disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.uni-select__label {
font-size: 16px;
// line-height: 22px;
height: 50px;
padding-right: 10px;
color: $uni-secondary-color;
}
.uni-select__input-box {
height: 35px;
width: 0px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-select__input {
flex: 1;
font-size: 16px;
height: 22px;
line-height: 22px;
}
.uni-select__input-plac {
font-size: 16px;
color: $uni-secondary-color;
}
.uni-select__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
left: 0;
width: 100%;
background-color: #ffffff;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3;
padding: 4px 0;
}
.uni-select__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0);
/* #endif */
}
/* #ifdef H5 */
@media (min-width: 768px) {
.uni-select__selector-scroll {
max-height: 200px;
}
}
/* #endif */
.uni-select__selector-empty,
.uni-select__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 35px;
font-size: 16px;
text-align: center;
/* border-bottom: solid 1px $uni-border-3; */
padding: 0px 10px;
}
.uni-select__selector-item:hover {
background-color: #f9f9f9;
}
.uni-select__selector-empty:last-child,
.uni-select__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.uni-select__selector__disabled {
opacity: 0.4;
cursor: default;
}
/* picker 弹出层通用的指示小三角 */
.uni-popper__arrow_bottom,
.uni-popper__arrow_bottom::after,
.uni-popper__arrow_top,
.uni-popper__arrow_top::after,
{
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow_bottom {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow_bottom::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-popper__arrow_top {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
bottom: -6px;
left: 10%;
margin-right: 3px;
border-bottom-width: 0;
border-top-color: #EBEEF5;
}
.uni-popper__arrow_top::after {
content: " ";
bottom: 1px;
margin-left: -6px;
border-bottom-width: 0;
border-top-color: #fff;
}
.uni-select__input-text {
// width: 280px;
width: 600rpx;
color: $uni-main-color;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
.uni-select__input-placeholder {
color: #333;
font-size: 16px;
}
.uni-select--mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 2;
}
.select-icon {
display: flex;
justify-content: center;
align-content: center;
justify-items: center;
}
.icon {
width: 18px;
height: 18px;
}
</style>
+109
View File
@@ -0,0 +1,109 @@
<!-- 较高的盒子组件 -->
<template>
<view class="care_box">
<!-- 添加按钮 -->
<view class="box_img">
<img src="../../static/images/catgroup.png" alt="" srcset="" class="img_icon">
</view>
<view class="box_content">
<view class="con_title">
添加我的宠物
</view>
<view class="con_sub">
<view class="sub_item">
补充品种
</view>
<view>
补充生日
</view>
</view>
<view class="con_content">
<!-- <view>
上次洗护:-
</view> -->
<view>
上次洗护时间:-
</view>
</view>
<nut-button size="small">添加宠物</nut-button>
</view>
</view>
</template>
<script setup>
</script>
<style lang="scss">
// page {
// --nut-button-default-bg-color: linear-gradient(90deg, #FFCD35 0%, #FFDE5E 100%);
// --nut-button-small-height: 60rpx;
// --nut-button-small-line-height: 60rpx;
// --nut-button-border-width: 0rpx;
// --nut-button-small-font-size: 28rpx;
// --nut-button-default-color: #312D22;
// }
.care_box {
--nut-button-default-bg-color: linear-gradient(90deg, #FFCD35 0%, #FFDE5E 100%);
--nut-button-small-height: 60rpx;
--nut-button-small-line-height: 60rpx;
--nut-button-border-width: 0rpx;
--nut-button-small-font-size: 28rpx;
--nut-button-default-color: #312D22;
width: 702rpx;
// height: 278rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 1rpx solid #FFCD35;
box-sizing: border-box;
padding: 24rpx;
display: flex;
flex-flow: row nowrap;
.box_img {
height: 96rpx;
width: 96rpx;
margin-right: 12rpx;
border-radius: 50%;
.img_icon {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.box_content {
display: flex;
flex-flow: column nowrap;
.con_title {
font-size: $uni-font-size-title;
color: $uni-text-color;
font-weight: 500;
margin-bottom: 10rpx;
}
.con_sub {
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
margin-bottom: 10rpx;
display: flex;
flex-flow: row nowrap;
.sub_item {
margin-right: 16rpx;
}
}
.con_content {
font-size: $uni-font-size-base;
color: $uni-text-color;
margin-bottom: 16rpx;
}
}
}
</style>
+44
View File
@@ -0,0 +1,44 @@
<!-- 较高的盒子组件 -->
<template>
<view class="gender_box">
<img src="../../static/images/Group6147.png" alt="" srcset="" v-if="gender === 0" class="img_icon">
<img src="../../static/images/Group6146.png" alt="" srcset="" v-else class="img_icon">
</view>
</template>
<script setup>
const props = defineProps({
gender: {
type: Number, // 接收的参数类型
default: 0, //默认值
}
})
</script>
<style lang="scss">
// page {
// --nut-button-default-bg-color: linear-gradient(90deg, #FFCD35 0%, #FFDE5E 100%);
// --nut-button-small-height: 60rpx;
// --nut-button-small-line-height: 60rpx;
// --nut-button-border-width: 0rpx;
// --nut-button-small-font-size: 28rpx;
// --nut-button-default-color: #312D22;
// }
.gender_box {
--nut-button-default-bg-color: linear-gradient(90deg, #FFCD35 0%, #FFDE5E 100%);
--nut-button-small-height: 60rpx;
--nut-button-small-line-height: 60rpx;
--nut-button-border-width: 0rpx;
--nut-button-small-font-size: 28rpx;
--nut-button-default-color: #312D22;
width: 28rpx;
height: 28rpx;
.img_icon {
width: 100%;
height: 100%;
}
}
</style>
+129
View File
@@ -0,0 +1,129 @@
<!-- 较高的盒子组件 -->
<template>
<view class="care_box">
<!-- 添加按钮 -->
<view class="box_img">
<img :src="detail.petInfo.headImgUrl || defalitImg" alt="" srcset="" class="img_icon">
</view>
<view class="box_content">
<view class="con_title">
{{ detail.petInfo.nickName }}
</view>
<view class="con_sub">
<Gender :gender="detail.petInfo.gender"></Gender>
<view class="sub_item">
{{ detail.petBaseInfo.assortment }}
</view>
<view>
{{ detail.petInfo.birthday }}
</view>
</view>
<view class="con_content">
<!-- <view>
上次洗护:{{ detail.petInfo.lastServiceProj }}
</view> -->
<view>
上次洗护时间:{{ detail.petInfo.lastServiceDate }}
</view>
</view>
<nut-button size="small">再来一单</nut-button>
</view>
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import Gender from '../gender'
const defalitImg = ref('../../static/images/catgroup.png')
const components = { 'Gender': Gender, };
const props = defineProps({
detail: {
type: Object, // 接收的参数类型
default: {}, //默认值
}
})
// const { detail } = toRefs(props)
onLoad(() => {
console.log({ detail });
})
</script>
<style lang="scss">
// page {
// --nut-button-default-bg-color: linear-gradient(90deg, #FFCD35 0%, #FFDE5E 100%);
// --nut-button-small-height: 60rpx;
// --nut-button-small-line-height: 60rpx;
// --nut-button-border-width: 0rpx;
// --nut-button-small-font-size: 28rpx;
// --nut-button-default-color: #312D22;
// }
.care_box {
--nut-button-default-bg-color: linear-gradient(90deg, #FFCD35 0%, #FFDE5E 100%);
--nut-button-small-height: 60rpx;
--nut-button-small-line-height: 60rpx;
--nut-button-border-width: 0rpx;
--nut-button-small-font-size: 28rpx;
--nut-button-default-color: #312D22;
width: 528rpx;
// height: 278rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 1rpx solid #FFCD35;
box-sizing: border-box;
padding: 24rpx;
display: flex;
margin-right: 20rpx;
flex-flow: row nowrap;
.box_img {
height: 96rpx;
width: 96rpx;
margin-right: 16rpx;
border-radius: 50%;
.img_icon {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.box_content {
display: flex;
flex-flow: column nowrap;
.con_title {
font-size: $uni-font-size-lg;
color: $uni-text-color;
font-weight: 500;
margin-bottom: 10rpx;
}
.con_sub {
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
margin-bottom: 16rpx;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
.sub_item {
margin-left: 10rpx;
margin-right: 16rpx;
}
}
.con_content {
font-size: $uni-font-size-base;
color: $uni-text-color;
margin-bottom: 16rpx;
}
}
}
</style>
+55
View File
@@ -0,0 +1,55 @@
<!-- 较高的盒子组件 -->
<template>
<view class="header_box_container">
<view class="title">{{ title }}</view>
<view class="sub" :class="{ sub2: type == 'yellow' }">{{ sub }}</view>
</view>
</template>
<script setup>
import { toRefs } from 'vue'
const props = defineProps({
title: {
type: String, // 接收的参数类型
default: '', //默认值
},
sub: {
type: String, // 接收的参数类型
default: '', //默认值
},
// yellow grey
type: {
type: String, // 接收的参数类型
default: '', //默认值
},
})
const { title, sub, type } = toRefs(props)
</script>
<style lang="scss">
.header_box_container {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
.title {
font-size:14pt;
color: #444137;
font-weight: 600;
max-width: 400rpx;
}
.sub {
font-size: $uni-font-size-sm;
color: $uni-text-color-grey;
}
.sub2 {
color: $uni-color-primary;
}
}
</style>
+114
View File
@@ -0,0 +1,114 @@
<!-- 较高的盒子组件 -->
<template>
<div class="large-box" @tap="handleChangeType">
<!-- 添加按钮 -->
<div class="add-button" v-if="!ischeck">
+
</div>
<div class="add-button ischoose" v-if="ischeck">
<img src="../../static/images/chooseitem.png" alt="">
</div>
<div class="box-content">
<div class="con-title">{{ name }}</div>
<div class="con-num">¥{{ price }}</div>
</div>
<div class="box-icon">
<img :src="goodsIcon" alt="">
</div>
</div>
</template>
<script setup>
const emit = defineEmits(['goodschooseemit'])
const props = defineProps({
name: {
type: String,
default: ''
},
price: {
type: Number,
default: 0
},
goodsIcon: {
type: String,
default: ''
},
id: {
type: Number,
default: 0
},
ischeck: {
type: Boolean,
default: false
}
})
// const isChoose = ref(false)
function handleChangeType() {
// isChoose.value = !isChoose.value
emit('goodschooseemit', { id: props.id, ischeck: !props.ischeck })
}
</script>
<style lang="scss">
.large-box {
position: relative;
height: 150rpx;
width: 240rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 2rpx solid #E5E4E4;
overflow: hidden;
color: rgba(49, 45, 34, 1);
.add-button {
position: absolute;
background-color: #000;
top: -2rpx;
right: -2rpx;
width: 32rpx;
height: 32rpx;
color: rgba(217, 217, 217, 1);
// font-size:20rpx;
line-height: 32rpx;
text-align: center;
}
.box-content {
position: absolute;
top: 12rpx;
left: 24rpx;
// height:75rpx;
.con-title {
color: rgba(49, 45, 34, 1);
width: 188rpx;
font-weight: 500;
font-size:$uni-font-size-base;
// height: 28rpx;
margin-bottom: 8rpx;
}
.con-num {
color: rgba(49, 45, 34, 1);
font-size: 26rpx;
height: 26rpx;
}
}
.box-icon {
width: 68rpx;
height: 68rpx;
position: absolute;
right: 10rpx;
bottom: 10rpx;
}
.box-icon image {
width: 100%;
height: 100%;
}
}
</style>
+155
View File
@@ -0,0 +1,155 @@
<!-- 订单页面 -->
<template>
<view class="order_item">
<view class="order_content">
<view class="ord_con_icon">
<img :src=" imgUrl!='' ? imgUrl : defalitImg" alt="" srcset="" class="img_icon">
</view>
<view class="ord_con_content">
<view class="con_content_title">服务时间:{{ serverTime }}</view>
<div class="title_top">
<view class="con_content">用户ID:{{ uid }}</view>
<div class="info_price title_top_info" @tap="handlePetList()">
宠物列表
</div>
</div>
<view class="con_content">下单时间:{{ ordertime }}</view>
<view class="con_content">订单状态:{{ ordertype[cardtype] }}</view>
</view>
</view>
</view>
</template>
<script setup>
import headerBox from '../headerBox/index'
const defalitImg = ref('../../static/images/catgroup.png')
const emit = defineEmits([ 'petList'])
// 0:未派单,1:已派单"
// const ordertype = ['', '待服务
// ', '服务中', '已完成', '已取消']
const ordertype = ['未派单', '已派单']
const props = defineProps({
orderId: {
type: [String, Number],
default: 0
},
title: {
type: [String, Number],
default: '',
},
serverTime:{
type: String,
default: ''
},
ordertime: { //下单时间
type: String,
default: ''
},
uid: {
type: [String, Number],
default: ''
},
// 1待服务 2服务中 3已完成 4已派单 5已取消
cardtype: {
type: Number,
default: '',
},
imgUrl: {
type: String,
default: null
},
})
function handlePetList() {
emit('petList', {})
}
</script>
<style lang="scss" scoped>
.order_item {
width: 702rpx;
height: 308rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
box-sizing: border-box;
padding: 32rpx 24rpx 36rpx 24rpx;
display: flex;
flex-flow: column nowrap;
padding-bottom: 10rpx;
// margin-top: 24rpx;
.order_content {
display: flex;
flex-flow: row nowrap;
// margin-top: 22rpx;
height: 202rpx;
padding-bottom: 24rpx;
box-sizing: border-box;
// border-bottom: 1rpx solid #E5E4E4;
.ord_con_icon {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
.img_icon {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
}
}
.ord_con_content {
margin-left: 32rpx;
display: flex;
flex-flow: column nowrap;
.con_content_title {
font-size:38rpx;
font-weight: 500;
color: $uni-text-color;
display: flex;
}
.con_content {
margin-top: 20rpx;
color: #444137;
}
}
}
.button_box {
margin-top: 28rpx;
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
.item_button {
margin-left: 24rpx;
width: 176rpx;
height: 60rpx;
border-radius: 200rpx 200rpx 200rpx 200rpx;
border: 2rpx solid #BCB9AE;
text-align: center;
line-height: 60rpx;
color: #312D22;
}
}
}
.title_top {
width: 542rpx;
display: flex;
justify-content: space-between;
}
.title_top_info {
border-bottom: 1px solid #565656;
margin-right: 36rpx;
padding-top: 14rpx;
color: #565656;
font-size: 17px;
}
</style>
+98
View File
@@ -0,0 +1,98 @@
<!-- 较高的盒子组件 -->
<template>
<div class="small_box">
<!-- 添加按钮 -->
<div class="add-button" v-if="!isChoose" @tap="handleChangeType">
+
</div>
<div class="add-button ischoose" v-if="isChoose" @tap="handleChangeType">
<img src="../../static/images/chooseitem.png" alt="">
</div>
<div class="small_img_box">
<img :src="goodsIcon" alt="">
</div>
<div class="small_img_content">
<div>{{ name }}</div>
<div>¥{{ price }}</div>
</div>
</div>
</template>
<script setup>
const emit = defineEmits(['goodschooseemit'])
const props = defineProps({
name: {
type: String,
default: ''
},
price: {
type: Number,
default: 0
},
goodsIcon: {
type: String,
default: ''
},
id: {
type: Number,
default: 0
}
})
const isChoose = ref(false)
function handleChangeType() {
isChoose.value = !isChoose.value
emit('goodschooseemit', props.id)
}
</script>
<style lang="scss">
image {
width: 100%;
height: 100%;
}
.small_box {
position: relative;
height: 96rpx;
width: 240rpx;
padding-left: 12rpx;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 2rpx solid #E5E4E4;
overflow: hidden;
color: rgba(49, 45, 34, 1);
margin-right: 20rpx;
margin-bottom: 20rpx;
display: flex;
flex-flow: row nowrap;
align-items: center;
.add-button {
position: absolute;
background-color: #000;
top: -2rpx;
right: -2rpx;
width: 32rpx;
height: 32rpx;
color: rgba(217, 217, 217, 1);
line-height: 32rpx;
text-align: center;
}
.ischoose {
background-color: $uni-color-primary;
}
.small_img_box {
height: 56rpx;
width: 56rpx;
}
.small_img_content {
margin-left: 12rpx;
color: $uni-text-color;
font-size: $uni-font-size-sm;
}
}
</style>
+155
View File
@@ -0,0 +1,155 @@
<template>
<view class="swiper-container" :style="{ width: containerWidth }">
<swiper
:slides-per-view="slidesPerView"
:centered-slides="centeredSlides"
:loop="loop"
:space-between="spaceBetween"
:autoplay="autoplay"
:modules="modules"
class="mySwiper"
@slide-change="onSlideChange"
>
<swiper-slide v-for="(item, index) in items" :key="getKey(item, index)">
<view
class="slide-content"
:class="{ active: isActive(index) }"
:style="{
height: isActive(index) ? activeHeight : normalHeight,
width: isActive(index) ? activeWidth : normalWidth
}"
>
<slot name="slide" :item="item" :index="index">
<image class="slide-image" :src="item.image" :alt="item.alt || ''" mode="aspectFill" />
</slot>
</view>
</swiper-slide>
</swiper>
</view>
</template>
<script>
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Autoplay } from 'swiper';
import 'swiper/css';
import 'swiper/css/autoplay';
export default {
name: 'PetSwiper',
components: {
Swiper,
SwiperSlide
},
props: {
items: {
type: Array,
required: true,
default: () => []
},
containerWidth: {
type: String,
default: '80%'
},
slidesPerView: {
type: Number,
default: 3
},
centeredSlides: {
type: Boolean,
default: true
},
loop: {
type: Boolean,
default: true
},
spaceBetween: {
type: Number,
default: 20
},
autoplay: {
type: [Boolean, Object],
default: () => ({
delay: 3000,
disableOnInteraction: false
})
},
normalHeight: {
type: String,
default: '200px'
},
normalWidth: {
type: String,
default: '200px'
},
activeHeightIncrease: {
type: String,
default: '20px'
},
activeWidthIncrease: {
type: String,
default: '20px'
},
getKey: {
type: Function,
default: (item, index) => item.id || index
}
},
data() {
return {
modules: [Autoplay],
activeIndex: 0
};
},
computed: {
activeHeight() {
return `calc(${this.normalHeight} + ${this.activeHeightIncrease})`;
},
activeWidth() {
return `calc(${this.normalWidth} + ${this.activeWidthIncrease})`;
}
},
methods: {
onSlideChange(swiper) {
this.activeIndex = swiper.realIndex;
this.$emit('slide-change', swiper.realIndex);
},
isActive(index) {
return index === this.activeIndex % this.items.length;
}
}
};
</script>
<style scoped>
.swiper-container {
margin: 0 auto;
padding: 20px 0;
}
.mySwiper {
width: 100%;
height: 100%;
}
.slide-content {
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s ease;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
margin: 0 auto;
}
.slide-image {
width: 100%;
height: 100%;
object-fit: cover;
}
/* 两侧幻灯片样式 */
.swiper-slide:not(.swiper-slide-active) .slide-content {
opacity: 0.7;
}
</style>
+163
View File
@@ -0,0 +1,163 @@
<!-- 头像的盒子组件 -->
<template>
<!-- 无值输入时 -->
<div class="hb_main">
<scroll-view class="hb_box" scroll-x="true">
<!-- 有值输入时 -->
<div class="hb_box_list">
<div class="headerbox-container" v-for="(item, index) in petsList" :key="index"
@tap="choosepetbox(1, index, item)">
<!-- 头像框 -->
<div class="headerbox-title" :class="{ ischeck: item.petInfo.ischeck }">
<div class="header_img_box">
<img :src="item.petInfo.headImgUrl == '' ? '../../static/images/catgroup.png' : item.petInfo.headImgUrl"
alt="">
</div>
<!-- 小选择框 -->
<div class="checkbox" :class="{ ischoose: item.petInfo.ischoose }"
@tap.stop="handleinshoplist(item, index)">
<img v-if="item.petInfo.ischoose" src="../../static/images/Vector.png" alt="">
</div>
</div>
<div class="header-content">
{{ item.petInfo.nickName }}
</div>
</div>
<!-- 最后一个 -->
<div class="headerbox-container" @tap="choosepetbox(2)">
<div class="headerbox-title">
<div class="addpet header_img_box">
<img src="../../static/images/shopaddpet.png" alt="">
</div>
</div>
<div class="header-content">
添加宠物
</div>
</div>
</div>
</scroll-view>
</div>
</template>
<script setup>
import { ref } from 'vue'
const emit = defineEmits(['choosepet'])
const props = defineProps({
petsList: {
type: Array,
default: []
}
})
function handleinshoplist(item) {
item.petInfo.ischoose = !item.petInfo.ischoose
}
function choosepetbox(e, index, item) {
if (e === 1) {
for (let i in props.petsList) {
props.petsList[i].petInfo.ischeck = false
}
item.petInfo.ischeck = true
item.petInfo.ischoose = true
emit('choosepet', index)
} else if (e === 2) {
uni.navigateTo({
url: `/pages/petpage/index`
})
}
}
</script>
<style scoped lang="scss">
.hb_main {
padding: 24rpx;
padding-top: 60rpx;
box-sizing: border-box;
.hb_box {
width: 702rpx;
height: 216rpx;
padding: 24rpx;
box-sizing: border-box;
background-color: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
.hb_box_list {
display: flex;
flex-flow: row nowrap;
align-items: center;
.headerbox-container {
height: 170rpx;
width: 112rpx;
margin-right: 48rpx;
.headerbox-title {
width: 112rpx;
height: 112rpx;
margin-bottom: 16rpx;
border-radius: 56px;
background-color: #E5E4E4;
position: relative;
display: flex;
align-items: center;
justify-content: center;
.addpet {
background-color: #FFFFFF;
width: 112rpx !important;
height: 112rpx !important;
}
.header_img_box {
width: 102rpx;
height: 102rpx;
border-radius: 50%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.checkbox {
width: 40rpx;
height: 40rpx;
position: absolute;
bottom: 0rpx;
right: 0rpx;
border: 2rpx solid #FFCD35;
border-radius: 50%;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
image {
height: 40%;
width: 50%;
}
}
.ischoose {
background-color: #FFCD35;
}
}
.ischeck {
background-color: #FFCD35;
}
.header-content {
text-align: center;
font-size: $uni-font-size-base;
color: $uni-text-color;
}
}
}
}
}
</style>
+561
View File
@@ -0,0 +1,561 @@
<template>
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{label + ':'}}</span>
<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
<view class="uni-select" :class="{'uni-select--disabled':disabled}">
<view class="uni-select__input-box" @click="toggleSelector">
<view v-if="current" class="uni-select__input-text">{{textShow}}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
<view key="clear-button" v-if="current && clear && !disabled" @click.stop="clearVal">
<image class="icon" src="../../static/images/delete.png" mode="aspectFill"></image>
</view>
<view key="arrow-button" v-else class="select-icon">
<image v-if="showSelector" class="icon" src="../../static/images/down_arrow.png"
mode="aspectFill"></image>
<image v-else class="icon" src="../../static/images/ringht_arrow.png" mode="aspectFill"></image>
</view>
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" :style="getOffsetByPlacement" v-if="showSelector">
<view :class="placement=='bottom'?'uni-popper__arrow_bottom':'uni-popper__arrow_top'"></view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
<text>{{emptyTips}}</text>
</view>
<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData"
:key="index" @click="change(item)">
<text
:class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "Selecter",
mixins: [uniCloud.mixinDatacom || {}],
props: {
localdata: {
type: Array,
default () {
return []
}
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
emptyTips: {
type: String,
default: '无选项'
},
clear: {
type: Boolean,
default: true
},
defItem: {
type: Number,
default: 0
},
disabled: {
type: Boolean,
default: false
},
format: {
type: String,
default: ''
},
placement: {
type: String,
default: 'bottom'
}
},
data() {
return {
showSelector: false,
current: '',
mixinDatacomResData: [],
apps: [],
channels: [],
cacheKey: "uni-data-select-lastSelectedValue",
};
},
created() {
this.debounceGet = this.debounce(() => {
this.query();
}, 300);
if (this.collection && !this.localdata.length) {
this.debounceGet();
}
},
computed: {
typePlaceholder() {
const text = {
}
const common = this.placeholder
const placeholder = text[this.collection]
return common
},
valueCom() {
// #ifdef VUE3
return this.modelValue;
// #endif
// #ifndef VUE3
return this.value;
// #endif
},
textShow() {
// 长文本显示
let text = this.current;
return text;
},
getOffsetByPlacement() {
switch (this.placement) {
case 'top':
return "bottom:calc(100% + 12px);";
case 'bottom':
return "top:calc(100% + 12px);";
}
}
},
watch: {
localdata: {
immediate: true,
handler(val, old) {
if (Array.isArray(val) && old !== val) {
this.mixinDatacomResData = val
}
}
},
valueCom(val, old) {
this.initDefVal()
},
mixinDatacomResData: {
immediate: true,
handler(val) {
if (val.length) {
this.initDefVal()
}
}
},
},
methods: {
debounce(fn, time = 100) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, time)
}
},
// 执行数据库查询
query() {
this.mixinDatacomEasyGet();
},
// 监听查询条件变更事件
onMixinDatacomPropsChange() {
if (this.collection) {
this.debounceGet();
}
},
initDefVal() {
let defValue = ''
if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
defValue = this.valueCom
} else {
let strogeValue
if (this.collection) {
strogeValue = this.getCache()
}
if (strogeValue || strogeValue === 0) {
defValue = strogeValue
} else {
let defItem = ''
if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
defItem = this.mixinDatacomResData[this.defItem - 1].value
}
defValue = defItem
}
if (defValue || defValue === 0) {
this.emit(defValue)
}
}
const def = this.mixinDatacomResData.find(item => item.value === defValue)
this.current = def ? this.formatItemName(def) : ''
},
/**
* @param {[String, Number]} value
* 判断用户给的 value 是否同时为禁用状态
*/
isDisabled(value) {
let isDisabled = false;
this.mixinDatacomResData.forEach(item => {
if (item.value === value) {
isDisabled = item.disable
}
})
return isDisabled;
},
clearVal() {
this.emit('')
this.current = ''
if (this.collection) {
this.removeCache()
}
},
change(item) {
console.log('1=======',item)
if (!item.disable) {
this.showSelector = false
this.current = this.formatItemName(item)
this.emit(item.value)
}
},
emit(val) {
this.$emit('input', val)
this.$emit('update:modelValue', val)
this.$emit('change', val)
if (this.collection) {
this.setCache(val);
}
},
toggleSelector() {
if (this.disabled) {
return
}
this.showSelector = !this.showSelector
},
formatItemName(item) {
let {
text,
value,
channel_code
} = item
channel_code = channel_code ? `(${channel_code})` : ''
if (this.format) {
// 格式化输出
let str = "";
str = this.format;
for (let key in item) {
str = str.replace(new RegExp(`{${key}}`, "g"), item[key]);
}
return str;
} else {
console.log('this.collection======', this.collection)
return this.collection.indexOf('app-list') > 0 ?
`${text}(${value})` :
(
text ?
text :
`未命名${channel_code}`
)
}
},
// 获取当前加载的数据
getLoadData() {
return this.mixinDatacomResData;
},
// 获取当前缓存key
getCurrentCacheKey() {
return this.collection;
},
// 获取缓存
getCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
return cacheData[name];
},
// 设置缓存
setCache(value, name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
cacheData[name] = value;
uni.setStorageSync(this.cacheKey, cacheData);
},
// 删除缓存
removeCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
delete cacheData[name];
uni.setStorageSync(this.cacheKey, cacheData);
},
}
}
</script>
<style lang="scss">
$uni-base-color: #6a6a6a !default;
$uni-main-color: #333 !default;
$uni-secondary-color: #909399 !default;
$uni-border-3: #e5e5e5;
/* #ifndef APP-NVUE */
@media screen and (max-width: 500px) {
.hide-on-phone {
display: none;
}
}
/* #endif */
.uni-stat__select {
display: flex;
align-items: center;
// padding: 15px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
width: 300rpx;
flex: 1;
box-sizing: border-box;
}
.uni-stat-box {
background-color:rgba(0, 0, 0, 0); // #fff;
width: 100%;
flex: 1;
// background-color: aqua;
}
.uni-stat__actived {
width: 100%;
flex: 1;
// outline: 1px solid #2979ff;
}
.uni-label-text {
font-size: 14px;
font-weight: bold;
color: $uni-base-color;
margin: auto 0;
margin-right: 5px;
}
.uni-select {
font-size: 14px;
// border: 1px solid $uni-border-3;
box-sizing: border-box;
border-radius: 4px;
padding: 0 5px;
padding-left: 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
user-select: none;
/* #endif */
flex-direction: row;
align-items: center;
// border-bottom: solid 1px $uni-border-3;
width: 100%;
flex: 1;
height: 50px;
&--disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.uni-select__label {
font-size: 16px;
// line-height: 22px;
height: 50px;
padding-right: 10px;
color: $uni-secondary-color;
}
.uni-select__input-box {
height: 35px;
width: 0px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-select__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-select__input-plac {
font-size: 14px;
color: $uni-secondary-color;
}
.uni-select__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
left: 0;
width: 100%;
background-color: #ffffff;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3;
padding: 4px 0;
}
.uni-select__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0);
/* #endif */
}
/* #ifdef H5 */
@media (min-width: 768px) {
.uni-select__selector-scroll {
max-height: 600px;
}
}
/* #endif */
.uni-select__selector-empty,
.uni-select__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 35px;
font-size: 14px;
text-align: center;
/* border-bottom: solid 1px $uni-border-3; */
padding: 0px 10px;
}
.uni-select__selector-item:hover {
background-color: #f9f9f9;
}
.uni-select__selector-empty:last-child,
.uni-select__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.uni-select__selector__disabled {
opacity: 0.4;
cursor: default;
}
/* picker 弹出层通用的指示小三角 */
.uni-popper__arrow_bottom,
.uni-popper__arrow_bottom::after,
.uni-popper__arrow_top,
.uni-popper__arrow_top::after,
{
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow_bottom {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow_bottom::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-popper__arrow_top {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
bottom: -6px;
left: 10%;
margin-right: 3px;
border-bottom-width: 0;
border-top-color: #EBEEF5;
}
.uni-popper__arrow_top::after {
content: " ";
bottom: 1px;
margin-left: -6px;
border-bottom-width: 0;
border-top-color: #fff;
}
.uni-select__input-text {
// width: 280px;
width: 200rpx;
color: $uni-main-color;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
.uni-select__input-placeholder {
color: #333;
font-size: 14px;
}
.uni-select--mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 2;
}
.select-icon {
display: flex;
justify-content: center;
align-content: center;
justify-items: center;
}
.icon {
width: 18px;
height: 18px;
}
</style>
+68
View File
@@ -0,0 +1,68 @@
<!-- 车辆item -->
<template>
<view class="time-slot" @click="$emit('click')">
<view class="time">{{ time }}</view>
<view class="status" :class="statusClass">{{ status }}</view>
<view class="order-status" :class="orderStatusClass">{{ orderStatus }}</view>
</view>
</template>
<script setup>
const props = defineProps({
time: String,
status: String,
orderStatus: String
});
const statusClass = computed(() => ({
'occupied': props.status === '已占用',
'unoccupied': props.status === '未占用'
}));
const orderStatusClass = computed(() => ({
'dispatched': props.orderStatus === '已派单',
'undispatched': props.orderStatus === '未派单'
}));
</script>
<style scoped>
.time-slot {
display: flex;
padding: 20rpx;
border-bottom: 1rpx solid #f5f5f5;
align-items: center;
}
.time {
width: 120rpx;
font-size: 28rpx;
}
.status, .order-status {
flex: 1;
text-align: center;
font-size: 26rpx;
padding: 5rpx 10rpx;
border-radius: 8rpx;
}
.occupied {
background-color: #FFEBEE;
color: #F44336;
}
.unoccupied {
background-color: #E8F5E9;
color: #4CAF50;
}
.dispatched {
background-color: #E3F2FD;
color: #2196F3;
}
.undispatched {
background-color: #FFF3E0;
color: #FF9800;
}
</style>
+278
View File
@@ -0,0 +1,278 @@
<template>
<div>
<nut-popup position="bottom" :visible="showbottom" @close="handleClose" closeable round>
<div class="time_popup_container">
<!-- title -->
<div class="titlebox">
预约时间
</div>
<!-- 宠物框 -->
<!-- <scroll-view class="time_day_list" scroll-x="true"> -->
<scroll-view class="time_day_list" scroll-x="true">
<div class="scroll_view_list_class">
<div v-for="(item, index) in timelists" :key="index" class="time_day_item"
@tap="handlechoooseDay(index)">
<div class="list_day" :class="{ yellow: item.ischeck }" >
{{ timedaylist[item.date] }}
</div>
<div class="list_date" :class="{ yellow: item.ischeck }">
{{ item.day }}
</div>
<div class="yellowbottom" v-if="item.ischeck"></div>
</div>
</div>
</scroll-view>
<!-- 价格框 -->
<div class="time_order_list">
<div v-for="(item, index) in showtimelist" :key="index" @tap="item.isOver ?null :handletimeitemlist(index)"
class="time_order_list_item" :class="{ isdisable:(item.occupy=='已占用' || item.isOver) , ischecked: item.ischeck }">
{{ item.time }}
</div>
</div>
<!-- 购买框 -->
<div class="bottom_box">
<div class="future_time">预计时间:{{ showtime }}</div>
<div class="button_class" @click="handleupdate">确认</div>
</div>
</div>
<nut-safe-area position="bottom"></nut-safe-area>
</nut-popup>
</div>
</template>
<script setup>
import { reactive, toRefs, watch } from 'vue';
const emit = defineEmits(['selfclose', 'uploadtime'])
const props = defineProps({
showbottomstates: {
type: Boolean,
default: false
},
timelists: {
type: Array,
default: []
}
})
const timedaylist = ref(['周日', '周一', '周二', '周三', '周四', '周五', '周六'])
const showtimelist = ref([])
const showtitle = ref([])
const showtime = ref('')
const backtime = ref('')
const isfirsttime = ref(true)
function handleupdate(e) {
console.log(backtime.value + ' ' + showtime.value)
if (showtime.value) {
emit('uploadtime', backtime.value + ' ' + showtime.value)
emit('selfclose', false)
}
}
function handletimeitemlist(e) {
isfirsttime.value = false
console.log(showtimelist.value[e])
for (let i in showtimelist.value) {
showtimelist.value[i].ischeck = false
}
if (!showtimelist.value[e].occupy=='已占用') {
return
}
console.log(showtimelist.value)
for (let i in props.timelists) {
if (props.timelists[i].ischeck) {
backtime.value = props.timelists[i].backtime
}
}
showtimelist.value[e].ischeck = true
showtime.value = showtimelist.value[e].time
console.log(showtimelist.value, '====3==== props.timelists')
}
function handlechoooseDay(e) {
isfirsttime.value = false
console.log('handlechoooseDay', e)
showtimelist.value.splice(0, showtimelist.value.length)
for (let i in props.timelists) {
props.timelists[i].ischeck = false
}
props.timelists[e].ischeck = true
backtime.value = props.timelists[e].backtime
console.log(props.timelists[e], '====2==== props.timelists')
showtimelist.value = JSON.parse(JSON.stringify(props.timelists[e].timelist))
console.log(showtimelist.value,'=========1======')
// props.timelists[e].timelist.forEach(element => {
// showtimelist.value.push(element)
// });
}
function isTimeGreaterThanCurrent(timeStr) {
const now = new Date();
const [hours, minutes] = timeStr.split(':').map(Number);
// 创建比较日期对象(使用今天的日期)
const compareDate = new Date(
now.getFullYear(),
now.getMonth(),
now.getDate(),
hours,
minutes
);
return compareDate > now;
}
function handleClose(e) {
showbottom.value = false
emit('selfclose', false)
}
watch(() => props.timelists, (newv, oldv) => {
if (newv && newv[0] && isfirsttime.value) {
console.log('--www----',props.timelists)
showtimelist.value = JSON.parse(JSON.stringify(props.timelists[0].timelist))
// if (showtimelist.value.length > 0) {
// showtimelist.value.splice(0, showtimelist.value.length)
// }
// newv[0].timelist.forEach(e => {
// // ischeck
// let data = { ...e, ischeck: false }
// showtimelist.value.push(JSON.parse(JSON.stringify(data)))
// })
}
}, { deep: true })
watch(() => props.showbottomstates, (newv, oldv) => {
console.log(newv, oldv)
showbottom.value = newv
})
const showbottom = ref(false)
</script>
<style lang="scss">
.time_popup_container {
height: 1000rpx;
.titlebox {
width: 750rpx;
height: 96rpx;
font-size: $uni-font-size-lg;
color: #000;
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
}
.time_day_list {
height: 112rpx;
width: 750rpx;
box-shadow: inset 0rpx -1rpx 0rpx 0rpx #E5E4E4;
padding-right: 30rpx;
box-sizing: border-box;
.scroll_view_list_class {
display: flex;
flex-flow: row nowrap;
height: 100%;
.time_day_item {
width: 76rpx;
text-align: center;
margin-right: 36rpx;
margin-left: 36rpx;
position: relative;
height: 100%;
.list_day {
color: $uni-text-color-grey;
font-size: $uni-font-size-sm;
margin-bottom: 16rpx;
}
.list_date {
color: $uni-text-color;
font-size: 30rpx;
}
.yellow {
color: $uni-color-primary !important;
}
.yellowbottom {
position: absolute;
bottom: 2rpx;
left: 25rpx;
width: 32rpx;
height: 4rpx;
background: $uni-color-primary;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
}
}
}
.time_order_list {
height: 664rpx;
padding: 11rpx;
box-sizing: border-box;
display: flex;
flex-flow: row wrap;
align-items: flex-start;
align-content: start;
.time_order_list_item {
width: 156rpx;
height: 96rpx;
background: #F3F3F3;
border-radius: 16rpx 16rpx 16rpx 16rpx;
text-align: center;
line-height: 96rpx;
box-sizing: border-box;
margin: 13rpx;
}
.isdisable {
background: #E5E5E5;
color: #BEBEBE;
}
.ischecked {
background: #FFCD35;
color: #312D22
}
}
.bottom_box {
height: 128rpx;
display: flex;
flex-flow: row nowrap;
padding: 0rpx 24rpx;
align-items: center;
justify-content: space-between;
.future_time {
font-size: 28rpx;
color: #312D22;
}
.button_class {
width: 240rpx;
height: 88rpx;
background: linear-gradient(270deg, #FFCD35 0%, #FFDE5E 100%);
border-radius: 74rpx 74rpx 74rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
}
}
.disabled-div {
pointer-events: none;
opacity: 0.6; /* 可选,让元素看起来是禁用的 */
}
}
</style>
+60
View File
@@ -0,0 +1,60 @@
Component({
data: {
selected: 0,
color: "#B8BBC3",
selectedColor: "#312D22",
key: 'tabbar_key',
list: [
{
pagePath: "/pages/index/index",
iconPath: "/static/images/home2.png",
selectedIconPath: "/static/images/home.png",
text: "订单"
},
{
pagePath: "/pages/user/index",
iconPath: "/static/images/user2.png",
selectedIconPath: "/static/images/user.png",
text: "车辆管理"
}
]
},
moved() {
console.log('moved')
},
attached() {
try {
console.log('attached')
this.setData({
list: [{
pagePath: "/pages/index/index",
iconPath: "/static/images/order.png",
selectedIconPath: "/static/images/order2.png",
text: "订单"
},
{
pagePath: "/pages/cars/index",
iconPath: "/static/images/car.png",
selectedIconPath: "/static/images/car2.png",
text: "车辆管理"
}]
})
} catch (e) {
// Do something when catch error
}
// 可以在这里控制显示
},
methods: {
switchTab(e) {
const data = e.currentTarget.dataset
const url = data.path
wx.switchTab({ url })
this.setData({
selected: data.index
})
}
}
})
+3
View File
@@ -0,0 +1,3 @@
{
"component": true
}
+7
View File
@@ -0,0 +1,7 @@
<!--miniprogram/custom-tab-bar/index.wxml-->
<cover-view class="tab-bar">
<cover-view wx:for="{{list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
<cover-image class="tab-bar-item-img" src="{{selected === index ? item.selectedIconPath : item.iconPath}}"></cover-image>
<cover-view style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</cover-view>
</cover-view>
</cover-view>
+28
View File
@@ -0,0 +1,28 @@
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 48px;
background: white;
display: flex;
padding-bottom: env(safe-area-inset-bottom);
box-shadow: 0rpx -1rpx 0rpx 0rpx #ECECEC;
}
.tab-bar-item {
flex: 1;
text-align: center;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
}
.tab-bar-item .tab-bar-item-img {
width: 27px;
height: 27px;
margin-right: 16rpx;
}
+15
View File
@@ -0,0 +1,15 @@
import {
createSSRApp
} from "vue";
import App from "./App.vue";
import store from './store';
export function createApp() {
console.log('createApp')
const app = createSSRApp(App);
app.use(store);
console.log('挂在pinia')
return {
app,
};
}
+78
View File
@@ -0,0 +1,78 @@
{
"name" : "",
"appid" : "__UNI__6999BC7",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App特有相关 */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* 模块配置 */
"modules" : {},
/* 应用发布信息 */
"distribute" : {
/* android打包配置 */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios打包配置 */
"ios" : {},
/* SDK配置 */
"sdkConfigs" : {}
}
},
/* 快应用特有相关 */
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"requiredPrivateInfos" : [ "chooseLocation", "getLocation" ],
"appid" : "wx047689e2fd64e87e",
"setting" : {
"urlCheck" : false
},
"permission" : {
"scope.userLocation" : {
"desc" : "你的位置信息将用于小程序位置接口的效果展示"
}
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3"
}
+107
View File
@@ -0,0 +1,107 @@
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
,
{
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/cars/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
,
{
"path": "pages/orderInfo/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/orderInfom/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/orderPetList/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/careorderinfoCleanList/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/orderEdit/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/addresslist/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/addressconfig/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/orderDispatch/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"custom": true,
"color": "#B8BBC3",
"selectedColor": "#312D22",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/cars/index",
"text": "分类"
}
]
}
}
+323
View File
@@ -0,0 +1,323 @@
<template>
<div class="address_list">
<nut-navbar :title="data.info.id ? '修改服务地址' : '添加服务地址'" :fixed="true" ref="navtest" left-show
:custom-color="'#312D22'" :safe-area-inset-top="true">
</nut-navbar>
<nut-form :model-value="data.info" ref="dataFrom" :rules="rules">
<nut-form-item prop="name">
<template v-slot:label>
<div class="nut_form_label_self">
姓名
</div>
</template>
<div class="input_border_box">
<nut-input v-model="data.info.name" input-class="nut-input-text" placeholder="请输入姓名" type="text"
@blur="customBlurValidate('name')" />
</div>
</nut-form-item>
<nut-form-item prop="mobile">
<template v-slot:label>
<div class="nut_form_label_self">
手机号
</div>
</template>
<div class="input_border_box">
<nut-input v-model="data.info.mobile" max-length="11" input-class="nut-input-text" placeholder="请输入手机号"
type="number" @blur="customBlurValidate('mobile')" />
</div>
</nut-form-item>
<!-- <nut-form-item prop="area">
<template v-slot:label>
<div class="nut_form_label_self">
所在地区
</div>
</template>
<div class="input_border_box">
<view @tap="typeShow = true">{{ data.info.area || '请选择所在地区' }}</view>
</div>
</nut-form-item> -->
<nut-form-item prop="addr">
<template v-slot:label>
<div class="nut_form_label_self">
地址
</div>
</template>
<div class="input_border_box">
<!-- <nut-textarea placeholder="街道、门牌号等" type="text" v-model="data.info.addr"
@blur="customBlurValidate('address')" /> -->
<view @tap="handleopenLocation" @blur="customBlurValidate('address')">{{ data.info.addr || '请选择服务地址' }}</view>
</div>
</nut-form-item>
</nut-form>
<div class="shopcar_box">
<div class="shopcar_box_list">
<!-- 联系客服 -->
<div class="box_list_button" @tap="saveAddress()">
保存使用
</div>
</div>
<nut-safe-area position="bottom"></nut-safe-area>
</div>
<nut-popup v-model:visible="typeShow" position="bottom" safe-area-inset-bottom>
<nut-picker :columns="addressList" :field-names="fieldNames" title="服务区域" @confirm="onAddressConfirm"
@cancel="typeShow = false" @change="customBlurValidate('area')"></nut-picker>
</nut-popup>
</div>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { serviceAddOrEdit, serviceAreaAddrList, serviceAddrLists } from '../../api/address'
import { useUserInfo } from '@/store'
const userInfo = useUserInfo()
const dataFrom = ref(null);
const typeShow = ref(false);
const addressList = ref([])
const data = reactive({
info: {
name: '',
mobile: '',
area: '',
addr: '',
arealatitudelongitude: '', //服务范围
longitude: null,
areaId: '',
arealatitudelatitude: '', //服务范围
latitude: null
},
uid: ''
});
const fieldNames = ref({
text: "addr",
value: "id",
});
const rules = reactive({
name: [
{ required: true, message: '请填写名称' },
],
mobile: [
{ required: true, message: '请选择联系方式' }
],
addr: [
{ required: true, message: '请输入街道、门牌号' }]
,
// area: [
// { required: true, message: '请选择省市区县、乡镇等' }]
})
function handleopenLocation() {
const test = data.info.latitude
console.log(test, 'test')
wx.chooseLocation({
latitude: data.info.latitude || null,
longitude: data.info.longitude || null,
success: (e) => {
console.log(e, '<<<<<<<<<<')
data.info.addr = e.address
data.info.longitude = e.longitude
data.info.latitude = e.latitude
console.log(data.info);
},
fail(e) {
console.log(e, 'fail')
}
})
}
onLoad((e) => {
if (e.uid && e.uid !== 'undefined') {
data.uid = e.uid
}
console.log(e.uid, '>>>>>>>>uid')
if (e.id && e.id !== 'undefined') {
serviceAddrLists(e.uid).then(res => {
if (res.code === 200) {
var newData = res.data
var item = newData.find(x => x.id === Number(e.id))
data.info = item
console.log(data.info, item);
}
})
}
serviceAreaAddrList({}).then(res => {
if (res.code === 200) {
addressList.value = res.data.serviceAddrList
}
})
})
function changeAddress() {
wx.chooseLocation({
latitude: data.info.arealatitudelatitude,
longitude: data.info.arealatitudelongitude,
success: (e) => {
data.info.area = e.address
data.info.longitude = e.longitude
data.info.latitude = e.latitude
console.log(data.info);
},
fail(e) {
console.log(e, 'fail')
}
})
}
function onAddressConfirm({ selectedValue, selectedOptions }) {
console.log(selectedValue, selectedOptions, '<<<<<<<<<<');
typeShow.value = false
var item = addressList.value.find(x => x.id === selectedOptions[0].id)
data.info.area = item.addr
data.info.arealatitudelongitude = item.longitude
data.info.arealatitudelatitude = item.latitude
data.info.areaId = item.id
console.log(data.info, item, selectedOptions);
customBlurValidate('area')
}
// 失去焦点校验
const customBlurValidate = (prop) => {
dataFrom.value.validate(prop).then(({ valid, errors }) => {
if (valid)
console.log('success')
else
console.log('error submit!!', errors)
})
}
function saveAddress() {
dataFrom.value.validate().then(({ valid, errors }) => {
if (valid) {
const params = {
...data.info
}
if (params.latitude && params.longitude) {
params.latitude = params.latitude.toString()
params.longitude = params.longitude.toString()
}
if (params.mobile.length < 11) {
uni.showModal({
title: '提示',
content: '请正确输入手机号',
showCancel: false,
confirmColor: '#FFCD35',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
return
}
let paramsEdit = {}
paramsEdit.addr = params.addr
paramsEdit.city = params.city || ''
paramsEdit.district = params.district || ''
paramsEdit.id = params.id
paramsEdit.latitude = params.latitude
paramsEdit.longitude = params.longitude
paramsEdit.mobile = params.mobile
paramsEdit.name = params.name
paramsEdit.province = params.province || ''
paramsEdit.uid = data.uid || 0
console.log(data.uid, '>>>>>>>>uiddd')
console.log(paramsEdit, "======")
serviceAddOrEdit(paramsEdit).then(res => {
if (res.code === 200) {
uni.showToast({
title: data.info.id ? '修改成功' : '新增成功',
//将值设置为 success 或者直接不用写icon这个参数
icon: 'success',
//显示持续时间为 2秒
duration: 2000
})
uni.navigateBack()
} else {
uni.showModal({
title: '提示',
content: res.msg,
})
}
});
} else {
console.log(errors[0].message);
}
})
}
</script>
<style lang="scss">
.nut-cell-group__wrap {
--nut-form-item-label-width: 50rpx;
box-shadow: 0px 0px 0px 0px !important;
--nut-form-item-label-font-size: 28rpx;
}
.nut-form-item__label {
font-weight: 500 !important;
font-size: 32rpx !important;
color: #312D22 !important;
}
.nut-input-text {
width: 526rpx;
height: 56rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 20rpx;
font-size: $uni-font-size-base;
}
.nut_form_label_self {
color: $uni-text-color;
margin-top: 28rpx;
display: inline-block;
}
.input_border_box {
padding: 20rpx;
box-sizing: border-box;
color: #333;
border: 1rpx solid #E5E4E4;
border-radius: 16rpx 16rpx 16rpx 16rpx;
}
.address_list {
background-color: #fff;
height: 100%;
}
.shopcar_box {
position: fixed;
bottom: 0px;
left: 0px;
background-color: #fff;
.shopcar_box_list {
height: 128rpx;
width: 750rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: 20rpx;
box-sizing: border-box;
.box_list_button {
width: 702rpx;
height: 88rpx;
background: linear-gradient(270deg, #FFCD35 0%, #FFDE5E 100%);
border-radius: 74rpx 74rpx 74rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
color: $uni-text-color;
}
}
}
</style>
+202
View File
@@ -0,0 +1,202 @@
<template>
<div class="pet_list">
<nut-navbar title="服务地址" :fixed="true" ref="navtest" left-show :safe-area-inset-top="true" :custom-color="'#312D22'">
</nut-navbar>
<div class="list_box" v-for="(address, index) in userServiceAddrList" :key="index"
v-if="userServiceAddrList && userServiceAddrList.length > 0">
<div class="list_item" :key="address" @tap="handlebackpage(address)">
<div class="list_item_top">
<div class="top_name">{{ address.name }}</div>
<div>{{ address.mobile }}</div>
</div>
<div class="list_item_bottom">{{ address.addr }}</div>
<div class="edit_icon" @tap.stop="handlegotoaddressinfo(address.id)">
<img src="../../static/images/edit2.png" alt="">
</div>
</div>
</div>
<div class="shopcar_box" v-if="userServiceAddrList && userServiceAddrList.length > 0">
<div class="shopcar_box_list">
<!-- 联系客服 -->
<div class="box_list_button" @tap="handlegotoaddressinfo()">
新增服务地址
</div>
</div>
<nut-safe-area position="bottom"></nut-safe-area>
</div>
<div v-else class="no-data">
<div class="content">
<img src="../../static/images/petdefault.png" alt="" class="no-img">
<div class="msg">暂无服务地址</div>
<nut-button size="large" type="primary" @tap="handlegotoaddressinfo()">去填写</nut-button>
</div>
</div>
</div>
</template>
<script setup>
import { onLoad, onShow } from '@dcloudio/uni-app';
import { serviceAddrLists } from '../../api/address'
const userServiceAddrList = ref([])
const isshoppageback = ref(false)
import {useUserInfo} from '@/store'
const userInfo = useUserInfo()
const addressUid = ref(0)
onShow(() => {
initList()
})
onLoad((e) => {
if (e.type == 2) {
isshoppageback.value = true
addressUid.value = e.uid
initList()
}
})
function initList(){
serviceAddrLists(addressUid.value).then(res => {
if (res.code === 200){
userServiceAddrList.value = res.data
console.log({ res });
}
})
}
function handlebackpage(e) {
// let pages = getCurrentPages()
// let prevPage = pages[pages.length - 2]
// console.log(prevPage,'prevPage')
// prevPage.$vm.getValue(e)
// uni.navigateBack({
// delta: 1
// })
if (isshoppageback.value) {
console.log(e.name, e.id, 'test')
uni.$emit('returnData', { e })
uni.navigateBack()
}
}
function handlegotoaddressinfo(id) {
uni.navigateTo({
url: `/pages/addressconfig/index?id=${id}&uid=${addressUid.value}`
})
}
</script>
<style lang="scss">
page {
--nut-navbar-background: #F3F3F3;
--nut-navbar-color: #312D22;
--nut-button-default-height: 60rpx;
--nut-button-primary-color: #312D22;
height: 100%;
}
image {
width: 100%;
height: 100%;
}
.no-data {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
min-height: calc(100vh - 150rpx);
.content {
text-align: center;
height: 100%;
.msg {
margin: 40rpx;
}
.no-img {
width: 262rpx;
height: 262rpx;
}
}
}
.pet_list {
background: #F3F3F3;
height: 100%;
.list_box {
padding: 24rpx;
box-sizing: border-box;
.list_item {
width: 702rpx;
// height: 152rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
padding: 24rpx;
box-sizing: border-box;
position: relative;
.list_item_top {
display: flex;
flex-flow: row nowrap;
align-items: center;
.top_name {
color: $uni-text-color;
font-size: $uni-font-size-title;
margin-right: 16rpx;
}
}
.list_item_bottom {
margin-top: 16rpx;
}
.edit_icon {
position: absolute;
top: 56rpx;
right: 24rpx;
width: 40rpx;
height: 40rpx;
}
}
}
}
.shopcar_box {
position: fixed;
bottom: 0px;
left: 0px;
background-color: #fff;
.shopcar_box_list {
height: 128rpx;
width: 750rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: 20rpx;
box-sizing: border-box;
.box_list_button {
width: 702rpx;
height: 88rpx;
background: linear-gradient(270deg, #FFCD35 0%, #FFDE5E 100%);
border-radius: 74rpx 74rpx 74rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
color: $uni-text-color;
}
}
}
</style>
+530
View File
@@ -0,0 +1,530 @@
<template>
<div class="clean_info">
<nut-navbar title="洗护记录" :fixed="true" ref="navtest" left-show :safe-area-inset-top="true"
:custom-color="'#312D22'">
</nut-navbar>
<div class="pet_card_item">
<div class="card-header">
<nut-row type="flex" justify="space-evenly">
<nut-col :span="8">
<img :src="petListItem.petInfo.headImgUrl || defalitImg" alt="pet-avatar" class="pet-avatar" />
</nut-col>
<nut-col :span="13">
<div class="pet-info" style="margin-left: -24rpx;">
<div class="pet-name">{{ petListItem.petInfo.nickName }}</div>
<div class="con_content">
<Gender :gender="petListItem.petInfo.gender"></Gender>
<div class="con_sub">{{ petListItem.petBaseInfo?.hair == 1 ? '长毛' : '短毛' }}</div>
<div class="con_sub">{{ calculateAgeShow(petListItem.petInfo?.birthday) }} </div>
</div>
</div>
</nut-col>
</nut-row>
</div>
<div v-show="petListItem.washLogDetailList?.length > 0" class="list_box"
v-for="(washItem, index) in petListItem.washLogDetailList">
<div v-if="index == 0" class="list_item" :key="washItem">
<div class="coupon-info-right">
<div style="width: 170rpx;">洗护时间:</div>
<div style="max-width: 270rpx; color: #8E8B7F; font-size: 11pt;">{{ washItem?.serviceTime }}
</div>
</div>
<div class="coupon-info-right_index ">
<div style="width: 170rpx;">洗护师:</div>
<div style="max-width: 270rpx; color: #8E8B7F; font-size: 11pt;">{{ washItem?.operatorName }}
</div>
</div>
<!-- 是否用优惠券 -->
<div class="coupon-info">
是否用优惠券 :{{ washItem?.coupon ? '使用' : '未使用' }}
</div>
<div class="wash-line" />
<!-- 洗护内容项目 -->
<div class="wash-items">
洗护内容项目: {{ washItem?.washContext }}
</div>
<div class="wash-line" />
<!-- 洗护照片 -->
<div class="wash-photos">
<div class="photo-title">洗护时的照片:</div>
<div class="photo-grid" v-if="washItem?.uploadList?.length > 0">
<div v-for="(photo, index) in washItem?.uploadList" :key="index" class="photo-item">
<img :src="photo.url" alt="洗护照片" class="photo-itemimage"
@click="previewPhoto(washItem?.uploadList, index)">
</div>
</div>
<div v-else class="img_no-data">
<div class="img_content">
暂无洗护时的照片
</div>
</div>
</div>
</div>
<div v-else class="list_item_normal">
<div class="coupon-info-normal">
<div style="width: 170rpx;">洗护时间:</div>
<div style="color: #8E8B7F; font-size: 11pt;">{{ washItem?.serviceTime }}</div>
</div>
<div class="coupon-info-normal ">
<div style="width: 170rpx;">洗护师:</div>
<div style="max-width: 470rpx; color: #8E8B7F; font-size: 11pt;">{{ washItem?.operatorName }}
</div>
</div>
<!-- 是否用优惠券 -->
<div class="coupon-info">
是否用优惠券 :{{ washItem?.coupon ? '使用' : '未使用' }}
</div>
<div class="wash-line" />
<!-- 洗护内容项目 -->
<div class="wash-items">
洗护内容项目: {{ washItem?.washContext }}
</div>
<div class="wash-line" />
<!-- 洗护照片 -->
<div class="wash-photos">
<div class="photo-title">洗护时的照片:</div>
<div class="photo-grid" v-if="washItem?.uploadList?.length > 0">
<div v-for="(photo, index) in washItem?.uploadList" :key="index" class="photo-item">
<img :src="photo.url" alt="洗护照片" class="photo-itemimage"
@click="previewPhoto(washItem?.uploadList, index)">
</div>
</div>
<div v-else class="img_no-data">
<div class="img_content">
暂无洗护时的照片
</div>
</div>
</div>
</div>
</div>
<div v-if="petListItem.washLogDetailList?.length == 0" class="no-data">
<div class="content">
<div class="msg">暂无洗护数据</div>
</div>
</div>
<nut-safe-area position="bottom"></nut-safe-area>
</div>
</div>
</template>
<script setup>
import {
onShow
} from '@dcloudio/uni-app';
import Gender from '../../components/gender'
const components = {
'Gender': Gender,
};
const defalitImg = ref('../../static/images/catgroup.png')
const petListItem = ref({})
import {
cleaningPetInfo
} from '../../api/cleaning.js'
import {
useSystemInfo,
useUserInfo
} from '@/store'
import {
calculateAge
} from '../../utils/date.js'
const itemId = ref('')
function init() {
uni.showLoading({
title: '加载中'
})
cleaningPetInfo(itemId.value).then(res => {
uni.hideLoading()
if (res.code == 200) {
petListItem.value = res.data
} else {
uni.showToast({
title: "暂无洗护数据",
icon: 'error'
})
}
})
}
onShow((e) => {
// init()
})
onLoad((e) => {
if (e.id && e.id !== 'undefined') {
itemId.value = e.id
init()
}
})
// 预览图片
function previewPhoto(images, index) {
uni.previewImage({
current: index,
urls: images.map(item => item.url),
longPressActions: {
itemList: ['保存图片'], // 长按时显示的操作菜单项,如['保存图片', '转发']
itemColor: '#000000', // 可选,按钮文字颜色,默认#000000
// 用户长按并点击菜单项后的成功回调
success: (res) => {
// res.tapIndex 为用户点击的按钮索引,对应 itemList 中的顺序:cite[1]
if (res.tapIndex === 0) { // 假设用户点击了'保存图片'
// 注意:此处建议先下载网络图片到临时路径,再保存:cite[3]:cite[5]
downloadAndSaveImage(images[res.index].url); // res.index 为长按图片的索引:cite[1]
}
},
fail: (err) => {
console.log('长按操作失败:', err);
}
}
})
}
function downloadAndSaveImage(imageUrl) {
// 1. 下载图片到本地临时路径
uni.downloadFile({
url: imageUrl,
success: (downloadRes) => {
if (downloadRes.statusCode === 200) {
// 2. 将临时路径的图片保存到系统相册
uni.saveImageToPhotosAlbum({
filePath: downloadRes.tempFilePath, // 下载得到的临时文件路径
success: () => {
uni.showToast({
title: '保存成功',
icon: 'success'
});
},
fail: (saveErr) => {
console.error('保存失败:', saveErr);
// 处理保存失败,例如用户拒绝授权
if (saveErr.errMsg.indexOf('auth deny') !== -1 || saveErr.errMsg.indexOf('auth denied') !== -1) {
uni.showModal({
title: '提示',
content: '需要您授权保存图片到相册权限',
success: (modalRes) => {
if (modalRes.confirm) {
// 引导用户打开授权设置
uni.openSetting();
}
}
});
} else {
uni.showToast({
title: '保存失败',
icon: 'none'
});
}
}
});
}
},
fail: (downloadErr) => {
console.error('下载图片失败:', downloadErr);
uni.showToast({
title: '下载图片失败,请重试',
icon: 'none'
});
}
});
}
function calculateAgeShow(age) {
return age != undefined ? calculateAge(age) : '---'
}
</script>
<style lang="scss">
page {
--nut-navbar-background: #F3F3F3;
--nut-navbar-color: #312D22;
height: 100%;
}
.clean_info {
height: 100%;
background: #F3F3F3;
// background-color: #FFCD35;
// padding: 20rpx;
}
.nut-button--default {
border: 2rpx solid #312D22 !important;
}
.pet_card_item {
min-height: 100vh;
background-size: calc(100% - 20rpx) calc(100% - 240rpx);
background-position: top;
background-repeat: no-repeat;
background-attachment: fixed;
// /* 可选:固定背景不滚动 */
margin-bottom: 44rpx;
--nut-navbar-background: #F3F3F3;
--nut-navbar-color: #312D22;
--nut-button-default-height: 60rpx;
--nut-button-default-color: #312D22;
--nut-button-default-bg-color: #fff;
--nut-button-primary-color: #312D22;
justify-content: center;
/* 水平居中 */
align-items: center;
// padding: 14px;
}
.card-header {
padding-top: 14px;
align-items: center;
width: 100%;
}
.pet-avatar {
width: 124px;
height: 124px;
background: #FFF7DF;
border-radius: 24rpx 24rpx 24rpx 24rpx;
}
.pet-info {
display: flex;
flex-direction: column;
}
.pet-name {
font-size: 18px;
font-weight: bold;
margin-bottom: 5px;
}
.pet-desc {
color: #666;
margin-bottom: 3px;
}
.wash-info,
.washer-info {
color: #999;
font-size: 14px;
margin-bottom: 2px;
}
.coupon-info {
margin-top: 16px;
margin-bottom: 10px;
margin-left: 16px;
color: #444137;
}
.coupon-info-right {
// width: 224px;
flex: 1;
padding-left: 124rpx;
color: #444137;
margin-left: 84px;
margin-top: 6px;
display: flex;
align-items: flex-start;
margin-bottom: 14rpx;
}
.coupon-info-right_index {
width: 224px;
padding-left: 124rpx;
color: #444137;
margin-left: 84px;
margin-top: 6px;
display: flex;
align-items: flex-start;
margin-bottom: 24rpx;
}
.coupon-info-normal {
color: #444137;
margin-top: 16px;
display: flex;
align-items: flex-start;
margin-left: 16px;
margin-right: 16px;
}
.wash-items {
padding: 16px;
color: #444137;
}
.wash-line {
background-color: #FFCD35;
height: 0.5px;
margin-left: 16px;
margin-right: 16px;
}
.wash-photos {
margin-top: 15px;
margin-left: 16px;
margin-right: 16px;
padding: 10rpx;
border-radius: 16rpx;
border: 2rpx solid transparent;
border-color: #FFD140;
background-color: #FEFDDF;
}
.photo-title {
font-weight: bold;
// margin-left: 16px;
margin-bottom: 8px;
}
.photo-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.photo-item {
flex: auto;
// border-radius: 4px;
// border-radius: 16rpx;
// border: 0.5rpx solid transparent;
// border-color: #FFD140;
}
.photo-itemimage {
width: 82px;
height: 82px;
padding: 16rpx;
border-radius: 24rpx;
border: 0.5rpx solid transparent;
border-color: #FFD140;
}
.con_content {
display: flex;
align-items: center;
margin-bottom: 24rpx;
}
.con_sub {
font-size: $uni-font-size-base;
margin-left: 20rpx;
color: $uni-text-color-placeholder;
}
.con_con {
color: $uni-text-color;
font-size: $uni-font-size-base;
margin-bottom: 22rpx;
}
.petlist_bottom_box {
height: 128rpx;
}
.shopcar_box {
position: fixed;
bottom: 0px;
left: 0px;
background-color: #fff;
.shopcar_box_list {
height: 128rpx;
width: 750rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
// padding: 20rpx;
box-sizing: border-box;
.box_list_button {
width: 702rpx;
height: 88rpx;
background: linear-gradient(270deg, #FFCD35 0%, #FFDE5E 100%);
border-radius: 74rpx 74rpx 74rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
color: $uni-text-color;
}
}
}
.list_box {
box-sizing: border-box;
// margin-top: -150rpx;
.list_item {
margin-top: -140rpx;
width: 750rpx;
min-height: 298rpx;
background-color: rgba(255, 0, 0, 0);
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 12rpx;
box-sizing: border-box;
// position: relative;
display: flex;
flex-direction: column;
}
.list_item_normal {
width: 750rpx;
min-height: 298rpx;
background-color: rgba(255, 0, 0, 0);
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 12rpx;
box-sizing: border-box;
// position: relative;
display: flex;
flex-direction: column;
}
}
.no-data {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-top: 30%;
.content {
text-align: center;
height: 100%;
.msg {
margin: 40rpx;
}
.no-img {
width: 162rpx;
height: 162rpx;
}
}
}
.img_no-data {
width: 100%;
height: 100rpx;
display: flex;
align-items: center;
justify-content: center;
padding-top: 30rpx;
.img_content {
text-align: center;
height: 100%;
}
}
</style>
+474
View File
@@ -0,0 +1,474 @@
<template>
<div class="container">
<view class="nav_bar_box">
<nut-navbar :safe-area-inset-top="true" :custom-color="'#312D22'" :fixed="true" class="test">
<template #left class="hometitle">
管理后台
</template>
</nut-navbar>
</view>
<!-- 搜索 -->
<view class="search_box">
<Selecter v-model="carListVal" :localdata="carListOptions" @change="carChoose" placeholder="车辆信息">
</Selecter>
<div @click="dateShow = true" class="rightDate">
{{ dateVal[0] }} >
</div>
</view>
<!-- 车辆列表-->
<scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scrolltoupper="upper"
@scrolltolower="lower" @scroll="scroll" :style="{ height: scroll_list_height + 'px' }">
<view class="card-list" v-if="carOrderList && carOrderList.length > 0">
<div v-for="(car, index) in carOrderList" :key="index" v-if="carOrderList && carOrderList.length > 0">
<div class="card-item" :style="car?.occupy === '已占用' ? yellostatue : greenstatue">
<div class="icon_text_stop" v-if="car?.occupy == '未占用' && car?.dispatch == '未派单'"
@click="handleDateItem(car)">下架</div>
<div class="icon_text_stop" style="color:#ffcc33 ;" v-if="car?.occupy == '已下架'"
@click="handleDeleteDateItem(car)">解冻</div>
<div class="lineItem">
<img src="../../static/images/carTime.png" alt="" class="iconsmall">
<div class="icon_text">{{ car?.time }}</div>
</div>
<div class="lineItem">
<img src="../../static/images/carStop.png" alt="" class="iconsmall">
<div class="icon_text">{{ car?.occupy }}</div>
</div>
<div class="lineItem">
<img src="../../static/images/carOrder.png" alt="" class="iconsmall">
<div class="icon_text">{{ car?.dispatch }}</div>
</div>
</div>
</div>
</view>
<div v-else class="no-data">
<div class="content">
<img src="../../static/images/petdefault.png" alt="" class="no-img">
<div class="msg">暂无数据</div>
</div>
</div>
<nut-popup v-model:visible="dateShow" position="bottom">
<!-- <nut-date-picker v-model="dateVal" :min-date="min" :max-date="max" :three-dimensional="false"
@confirm="confirm"></nut-date-picker> -->
<nut-picker v-model="dateVal" :columns="dateOptions" :field-names="fieldNames" title="日期选择"
@cancel="dateShow = false" @confirm="confirm"></nut-picker>
</nut-popup>
</scroll-view>
<div class="petlist_bottom_box"></div>
<nut-safe-area position="bottom"></nut-safe-area>
</div>
</template>
<script setup>
const {
ctx
} = getCurrentInstance()
import Selecter from '../../components/selecter'
import {
ref
} from 'vue';
import {
carList, carAddDownTime, carDeleteDownTime
} from '../../api/cars';
import {
useSystemInfo,
useUserInfo
} from '@/store'
import {
onShow
} from '@dcloudio/uni-app';
import {
completeTime,
addHours
} from '../../utils/date.js'
const systemInfo = useSystemInfo()
const userInfo = useUserInfo()
const carListVal = ref('')
const carListOptions = ref([])
const dateOptions = ref([])
const carListAll = ref([])
const dateShow = ref(false)
const min = new Date(2020, 0, 1)
const max = new Date(2025, 10, 1)
const dateVal = ref([])
const carOrderList = ref([]);
const yellostatue = ref({
backgroundColor: '#FFD243'
})
const greenstatue = ref({
backgroundColor: '#00D237'
})
const postData = reactive({
age: null,
district: null,
gender: null,
pageNum: 1,
pageSize: 20,
petType: null,
uid: userInfo.getUid
})
//页面数据初始化
onLoad(() => {
// init()
})
onShow(() => {
if (typeof ctx.$scope.getTabBar === 'function' && ctx.$scope.getTabBar()) {
ctx.$scope.getTabBar().setData({
// 当前页面对应的tab index
selected: 1,
})
}
init()
if (typeof ctx.$scope.getTabBar === 'function' && ctx.$scope.getTabBar()) {
ctx.$scope.getTabBar().setData({
// 当前页面对应的tab index
selected: 1,
})
}
})
function init() {
carList(userInfo.getUid).then(res => {
console.log(res.code, '>>>>>>>')
if (res.code == 200) {
carListAll.value = res.data
dateOptions.value = res.data.map(item => {
return {
text: item.serviceDate,
value: item.serviceDate
};
});
if (dateVal.value?.length == 0) {
dateVal.value = [res.data[0].serviceDate]
}
carListOptions.value = res.data[0].carDispatchList.map(item => {
return {
text: item.carNo,
value: item.carId
};
});
if (carListVal.value == '') {
carListVal.value = carListOptions.value[0].value
}
carOrderList.value = findCarDispatchList(carListAll.value, dateVal.value[0], carListVal.value)
}
})
}
//冻结
function handleDateItem(car) {
let params = {
carId: parseInt(carListVal.value),
pageNum: 0,
pageSize: 10,
downDate: dateVal.value[0],
downHour: parseInt(car.time.split(':')[0], 10)
}
console.log(params, '>>>>>111>')
carAddDownTime(params).then(res => {
if (res.code == 200) {
uni.showToast({
title: '下架成功',
icon: 'success',
duration: 2000
})
init()
} else {
uni.showToast({
title: '下架失败,请稍后重试',
icon: 'success',
duration: 2000
})
}
})
}
function handleDeleteDateItem(car) {
let params = {
carId: parseInt(carListVal.value),
pageNum: 0,
pageSize: 10,
downDate: dateVal.value[0],
downHour: parseInt(car.time.split(':')[0], 10)
}
console.log(params, '>>>>>111>')
carDeleteDownTime(params).then(res => {
if (res.code == 200) {
uni.showToast({
title: '解冻成功',
icon: 'success',
duration: 2000
})
init()
} else {
uni.showToast({
title: '解冻失败,请稍后重试',
icon: 'success',
duration: 2000
})
}
})
}
function search(res) {
console.log('search', text)
}
//车辆选择
function carChoose(val) {
console.log('=========', val)
carListVal.value = val
carOrderList.value = findCarDispatchList(carListAll.value, dateVal.value[0], carListVal.value)
}
const scroll_list_height = systemInfo.getscreenheight - systemInfo.getnavbarheight - 46
const scrollTop = ref(0)
function upper(e) {
// console.log(e)
}
function lower(e) {
postData.pageNum += 1
init()
}
function scroll(e) {
// console.log(e)
}
//日期选择
function confirm({
selectedValue,
selectedOptions
}) {
console.log(selectedValue[0], selectedOptions[0])
dateShow.value = false
dateVal.value = [selectedValue[0]]
const dateItem = carListAll.value.find(item => item.serviceDate === selectedValue[0]);
carListOptions.value = dateItem.carDispatchList.map(item => {
console.log(item, '=====item')
return {
text: item.carNo,
value: item.carId,
};
});
carListVal.value = carListOptions.value[0].value
carOrderList.value = findCarDispatchList(carListAll.value, selectedValue[0], carListVal.value)
}
//派单数据处理
function findCarDispatchList(data, targetDate, targetCarNo) {
// 1. 先按 serviceDate 查找日期项
const dateItem = data.find(item => item.serviceDate === targetDate);
if (!dateItem) return null; // 如果日期不存在,返回 null
// 2. 在 carDispatchList 中按 carNo 查找车辆
const carItem = dateItem.carDispatchList.find(car => car.carId === targetCarNo);
console.log('1=========', carItem)
return carItem.dispatchResults || null; // 返回找到的车辆数据(或 null)
}
</script>
<style lang="scss">
.hometitle {
color: $uni-text-color;
font-size: 20px;
/* font-family: 'Douyin Sans-Bold'; */
}
.container {
--nut-navbar-background: #F3F3F3;
--nut-navbar-color: #312D22;
background-color: #F3F3F3;
}
.title {
font-size: 20px;
font-weight: bold;
color: #333;
}
.add-icon {
width: 20px;
height: 20px;
margin-left: 8px;
font-size: 24px;
color: #999;
}
.con_box {
display: flex;
flex-flow: row nowrap;
align-items: center;
margin-left: 16px;
padding-top: 124rpx;
.con_title {
font-weight: 600;
font-size: 18px;
color: $uni-text-color;
}
.con_sub {
font-size: $uni-font-size-sm;
color: $uni-text-color-grey;
margin-left: 16rpx;
}
}
.search_box {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
height: 60rpx;
width: auto;
padding: 20rpx;
.rightDate {
padding-right: 20rpx;
}
}
.arrow {
display: inline-block;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #999;
transition: transform 0.3s;
}
.arrow-up {
transform: rotate(180deg);
}
.card-list {
width: 750rpx;
display: flex;
flex-wrap: wrap;
padding-left: 12px;
}
.card-item {
width: 330rpx;
height: 214rpx;
margin: 6px;
background-color: #f8f8f8;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: center;
align-items: center;
.lineItem {
display: flex;
width: 100%;
height: 55rpx;
align-content: center;
align-items: center;
// justify-content: center;
padding-left: 80rpx;
}
}
.icon {
width: 20px;
height: 20px;
margin-right: 4px;
}
.num {
font-size: 14px;
color: #fff;
}
.tab-text {
font-size: 12px;
color: #999;
margin-top: 2px;
}
.active.tab-text {
color: #ffcc33;
}
.blindlist_bottom_box {
height: 64rpx;
}
.scroll-Y {
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
}
.no-data {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
margin-top: 50%;
.content {
text-align: center;
height: 100%;
.msg {
margin: 40rpx;
}
.no-img {
width: 262rpx;
height: 262rpx;
}
}
}
.icon_text {
color: #FFFFFF;
font-size: 16px;
padding-left: 10rpx;
}
.icon_text_stop {
color: red;
font-size: 16px;
padding-left: 190rpx;
position: absolute;
padding-bottom: 140rpx;
}
.iconsmall {
width: 30rpx;
height: 30rpx;
margin-right: 9rpx;
}
.petlist_bottom_box {
height: 128rpx;
background-color: #F3F3F3;
}
</style>
+359
View File
@@ -0,0 +1,359 @@
<template>
<div class="order_list_container">
<view class="nav_bar_box">
<nut-navbar :safe-area-inset-top="true" :custom-color="'#312D22'" :fixed="true" class="test"
@click-back="goLogin">
<template #left class="hometitle">
<!-- <div @click="goLogin"> -->
管理后台
<!-- </div> -->
</template>
</nut-navbar>
</view>
<nut-tabs v-model="state.tab11value" type="smile" @change="changeTable">
<nut-tab-pane v-for="item in list" :key="item.id" :title="`${item.value}`" :pane-key="item.id">
<template #default>
<scroll-view :scroll-top="scrollTop" class="scroll-Y" :style="{ height: scroll_list_height + 'px' }"
:refresher-enable="true" :refresher-enabled="isOpenRefresh" :scroll-y="true"
:refresher-triggered="triggered" :refresher-threshold="100" @scrolltolower="lower"
@refresherrefresh="onRefresh" @refresherpulling="onPulling" :key="refreshKey">
<div v-for="(order, index) in showOrderList" :key="index"
v-if="showOrderList && showOrderList.length > 0">
<order-item @tap="handlegotoinfo(order)" :orderId="order?.id || 0"
:title="order?.name || ''" :serverTime="order?.serviceTime || ''"
:ordertime="order?.createTime || ''" :uid="order?.uid || ''"
:cardtype="order?.dispatchStatus || 0" :imgUrl="order?.headImgUrl || ''"
@petList="handPetlist(order)"></order-item>
<div style="height: 20rpx;"></div>
</div>
<div v-else class="no-data">
<div class="content">
<img src="../../static/images/petdefault.png" alt="" class="no-img">
<div class="msg">暂无订单</div>
</div>
</div>
</scroll-view>
</template>
</nut-tab-pane>
</nut-tabs>
</div>
</template>
<script setup>
import orderItem from '../../components/orderItem'
import {
reactive,
ref,
getCurrentInstance,
watch, nextTick
} from 'vue'
import {
onReady,
onShow,
onLoad
} from '@dcloudio/uni-app'
import {
useSystemInfo,
useUserInfo
} from '@/store'
import {
orderList,
} from '../../api/orders'
import {
systemConfigInfo
} from '../../api/system'
const userInfo = useUserInfo()
const systemInfo = useSystemInfo()
const scroll_list_height = systemInfo.getscreenheight - systemInfo.getnavbarheight - 46
const orderDetails = ref([])
const orderCancel = ref([]) //已取消
const orderStayService = ref([]) //待服务
const orderService = ref([]) //服务中
const orderOver = ref([]) //已完成
const phoneNumber = ref(0)
const isLogin = ref(false)
const _freshing = ref(false)
const triggered = ref(false)
const timeconfig = ref(null)
const isOpenRefresh = ref(true)
const list = [{
"id": '0',
"value": '全部'
},
{
"id": '1',
"value": '待服务'
},
{
"id": '2',
"value": '服务中'
},
{
"id": '3',
"value": '已完成'
},
{
"id": '4',
"value": '已取消'
},
]
// 上下文
const {
ctx
} = getCurrentInstance()
const state = reactive({
tab11value: '0',
});
const showOrderList = ref([])
const refreshKey = ref(0)
// 监听数据变化
watch(showOrderList, (newVal) => {
console.log('订单列表更新,数量:', newVal.length)
// 数据变化后强制刷新scroll-view
refreshKey.value++
}, { deep: true })
const params = reactive({
orderStatus: 0,
pageNum: 0,
pageSize: 10,
uid: userInfo.uid
})
function changeTable() {
// 1待服务orderStayService 2服务中orderService 3已完成orderOver 4已取消orderCancel
showOrderList.value = []
if (state.tab11value == 0) {
showOrderList.value = orderDetails.value;
} else if (state.tab11value == 1) {
showOrderList.value = orderStayService.value
} else if (state.tab11value == 2) {
showOrderList.value = orderService.value
} else if (state.tab11value == 3) {
showOrderList.value = orderOver.value
} else if (state.tab11value == 4) {
showOrderList.value = orderCancel.value
}
}
function init(isadd) {
const paramsData = {
orderStatus: params.orderStatus,
pageNum: params.pageNum,
pageSize: params.pageSize,
uid: userInfo.getUid
}
console.log(paramsData, '--------------2')
try {
orderList(paramsData).then(res => {
if (res.content) {
var data = res.content || []
if (data.length > 0) {
for (let i in data) {
data[i].createTime = data[i].createTime.split(' ')[0] + ' ' + data[i].createTime.split(
' ')[1]
}
}
orderDetails.value = [...data]
// 1待服务 2服务中 3已完成 4已取消
orderStayService.value = orderStayService.value.concat(data.filter(x => x.orderStatus === 1))
orderService.value = orderService.value.concat(data.filter(x => x.orderStatus === 2))
orderOver.value = orderOver.value.concat(data.filter(x => x.orderStatus === 3))
orderCancel.value = orderCancel.value.concat(data.filter(x => x.orderStatus === 4))
if (isadd) {
showOrderList.value = [...showOrderList.value, ...orderDetails.value]
} else {
showOrderList.value = Array.isArray(orderDetails.value) ? [...orderDetails.value] : []
changeTable()
}
// 创建新数组引用
// showOrderList.value = Array.isArray(orderDetails.value) ? [...orderDetails.value] : []
// 强制刷新scroll-view
nextTick()
refreshKey.value++
}
})
systemConfigInfo({}).then(res => {
if (res.code === 200) {
phoneNumber.value = res.data.systemInfos.find(x => x.name === '客服电话')
}
})
} catch (error) {
console.error('加载订单失败:', error)
showOrderList.value = []
}
}
onShow(() => {
console.log(userInfo, '>>>>>>>userInfo')
isLogin.value = userInfo.getToken === 0 ? false : true
if (!isLogin.value) {
uni.navigateTo({
url: '/pages/login/index'
})
} else {
init(false);
}
if (typeof ctx.$scope.getTabBar === 'function' && ctx.$scope.getTabBar()) {
ctx.$scope.getTabBar().setData({
// 当前页面对应的tab index
selected: 0,
})
}
})
onLoad((e) => {
state.tab11value = e?.index !== undefined ? e?.index : '0'
// init()
// console.log(userInfo,'>>>>>>>>index>>>>>>',userInfo.getToken)
// isLogin.value = userInfo.getToken === 0 ? false : true
// if (!isLogin.value) {
// uni.navigateTo({
// url: '/pages/login/index'
// })
// } else {
// init();
// state.tab11value = 0
// changeTable()
// }
})
onReady((e) => { })
const scrollTop = ref(0)
function upper(e) {
// console.log(e)
}
function lower(e) {
params.pageNum += 1
console.log(showOrderList.value.length, '--------------a3')
init(true)
console.log(e)
}
function scroll(e) {
}
function onPulling(e) {
console.log("onpulling", e);
if (e.detail.deltaY < 0) return // 防止上滑页面也触发下拉
// console.log('触发下拉刷新')
triggered.value = true;
}
function onRefresh() {
console.log("onRefresh");
if (_freshing.value) return;
_freshing.value = true;
if (timeconfig.value) {
clearTimeout(timeconfig.value)
timeconfig.value = null
}
timeconfig.value = setTimeout(() => {
triggered.value = false;
_freshing.value = false;
console.log('开始请求')
// this.getData();
params.pageSize = 10
params.pageNum = 0
params.orderStatus = 0
orderDetails.value = []
orderStayService.value = []
orderService.value = []
orderOver.value = []
orderCancel.value = []
console.log(showOrderList.value.length, '--------------a4')
init(false)
}, 500);
}
//跳转订单详情
function handlegotoinfo(order) {
uni.navigateTo({
url: `/pages/orderInfom/index?orderInfo=${JSON.stringify(order)}`
})
}
//跳转宠物列表
function handPetlist(list) {
uni.navigateTo({
url: `/pages/orderPetList/index?list=${JSON.stringify(list)}`
})
}
//切换登录
function goLogin() {
userInfo.resetUidAndToken()
uni.navigateTo({
url: `/pages/login/index`
})
}
</script>
<style lang="scss">
.hometitle {
color: $uni-text-color;
font-size: 20px;
}
.nut-tab-pane {
background: #F3F3F3 !important;
box-sizing: border-box !important;
padding: 0rpx !important;
position: relative !important;
}
.scroll-Y {
height: 100vh;
background: #F3F3F3;
// padding: 24rpx;
padding-left: 24rpx;
padding-right: 24rpx;
padding-top: 24rpx;
padding-bottom: 44rpx;
box-sizing: border-box;
}
.order_list_container {
--nut-navbar-background: #F3F3F3;
--nut-navbar-color: #312D22;
background-color: #F3F3F3;
}
.no-data {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
padding-top: 50%;
.content {
text-align: center;
height: 100%;
.msg {
margin: 40rpx;
}
.no-img {
width: 262rpx;
height: 262rpx;
}
}
}
</style>
+238
View File
@@ -0,0 +1,238 @@
<template>
<view class="nav_bar_box">
</view>
<view class="login-container" style="background-image:url(../../static/bg.png ) ;" alt="">
<div class="login-header">欢迎使用</div>
<form class="login-form" @submit.prevent="handleSubmit">
<div class="form-group">
<label for="username">请输入账号</label>
<input class="form-input" id="username" v-model="form.username" type="text" placeholder="输入你的ID"
@blur="validateField('username')">
<span class="error-message" v-if="errors.username">{{ errors.username }}</span>
</div>
<div class="form-group">
<label for="password">请输入密码</label>
<input class="form-input" id="password" v-model="form.password" type="password" placeholder="输入你的密码"
@blur="validateField('password')">
<span class="error-message" v-if="errors.password">{{ errors.password }}</span>
</div>
<button type="submit" class="login-btn" @click="handleSubmit">
{{ isSubmitting ? '登录中...' : '登录' }}
</button>
</form>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import {
getuser,
apiLogin,
updateUserInfo,
getUserInfo
} from '../../../src/api/UserService.js'
const userInfo = useUserInfo()
import {
useUserInfo
} from '@/store'
import {
useRouter
} from 'vue-router'
const router = useRouter()
// 表单数据
const form = ref({
username: '',
password: ''
})
// 错误信息
const errors = ref({
username: '',
password: ''
})
// 提交状态
const isSubmitting = ref(false)
// 验证规则
const rules = {
username: [{
required: true,
message: '请输入账号'
},
{
min: 4,
message: '账号长度不能少于4位'
}
],
password: [{
required: true,
message: '请输入密码'
},
{
min: 1,
message: '密码长度不能为空'
}
]
}
// 字段验证
const validateField = (field) => {
const value = form.value[field]
errors.value[field] = ''
for (const rule of rules[field]) {
if (rule.required && !value) {
errors.value[field] = rule.message
return false
}
if (rule.min && value.length < rule.min) {
errors.value[field] = rule.message
return false
}
}
return true
}
// 表单提交
const handleSubmit = async () => {
// 验证所有字段
let isValid = true
Object.keys(form.value).forEach(field => {
if (!validateField(field)) {
isValid = false
}
})
if (!isValid) return
try {
isSubmitting.value = true
apiLogin({
username: form.value.username,
password: form.value.password
}).then(res => {
console.log((res))
if(res.code==200 && res.data!=""){
// userInfo.$patch({ token: res.data, uid: form.value.username })
userInfo.$patch({ token:'Bearer '+res.data.token,uid:res.data.id ,username:res.data.username,nickName:res.data.nickname})
uni.switchTab({
url: `/pages/index/index`
})
}else{
uni.showToast({
icon: 'none',
title:res.msg
})
}
})
} catch (error) {
console.error('登录错误:', error)
alert('登录失败,请稍后重试')
} finally {
isSubmitting.value = false
}
}
</script>
<style scoped>
.login-container {
width: 100%;
height: 100vh;
justify-content: center;
background-size: cover;
.banner {
margin-bottom: 48rpx;
border-radius: 16rpx 16rpx 16rpx 16rpx;
overflow: hidden;
background-color: #FBF0D5;
}
}
.login-header {
font-size: 24px;
font-weight: bold;
text-align: center;
padding-top: 276rpx;
margin-bottom: 30px;
color: #333;
}
.login-form {
display: flex;
flex-direction: column;
gap: 40px;
padding: 36rpx 36rpx 36rpx 36rpx;
}
.form-group {
display: flex;
flex-direction: column;
gap: 8px;
padding-bottom: 46rpx;
}
.form-group label {
font-size: 14px;
color: #666;
}
.form-group input {
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.form-group input:focus {
outline: none;
border-color: #409eff;
}
.form-input {
background-color: #ffffff;
border-radius: 46rpx;
font-size: 12px;
}
.error-message {
color: #f56c6c;
font-size: 12px;
height: 20px;
}
.login-btn {
height: 88rpx;
background-color: #FFD243;
color: #444137;
border-radius: 44px;
font-size: 14px;
padding: 6px;
margin-top: 400rpx;
}
.login-btn:hover {
background-color: #FFD243;
}
.login-btn:disabled {
background-color: #999999;
cursor: not-allowed;
}
</style>
+505
View File
@@ -0,0 +1,505 @@
<template>
<div class="shop_page_container">
<nut-navbar title="订单编辑" :fixed="true" ref="navtest" left-show :safe-area-inset-top="true"
:custom-color="'#312D22'">
</nut-navbar>
<div class="base_box short_box">
<div class="short_item" style="border-bottom: 1px solid #E9E8E8;padding-bottom: 10px;">
<div class="short_item_title">订单号:{{orderItem?.orderId}}</div>
<div class="short_item_pay">{{orderItem?.payStatus == 1 ? '已支付' : '未支付'}}</div>
</div>
<div class="show_box_item" style="border-bottom: 1px solid #E9E8E8;padding-bottom: 10px;">
<div class="short_item_title">地址信息</div>
<div class="short_item_time">{{extractPhoneNumber( orderItem?.userServiceAddr) }}</div>
<div class="short_item_normal">{{orderItem?.addr }}</div>
</div>
<div class="show_box_item" style="border-bottom: 1px solid #E9E8E8;padding-bottom: 10px;">
<div class="short_item_title">宠物信息</div>
<div v-for="(item, index) in orderItem?.petList" :key="index">
<div class="short_item_time">{{ item?.nickName+' | '+item?.assortment+' | '+ item?.weight+'kg'}}</div>
<div class="short_item_normal">{{item?.goodsNameList }}</div>
</div>
</div>
</div>
<div class="show_box_item">
<div class="short_item_time">订单服务时长</div>
<div class="choose_box">
<nut-input v-model="showProjectServerTime" placeholder="请输入订单服务时长" type="number" >
<template #right>
分钟
</template>
</nut-input>
</div>
</div>
<div class="show_box_item">
<div class="short_item_time">服务时间</div>
<div class="choose_box" @tap="handleshowtimepopup">
<div class="con_content">{{ showtimeboxinfo }}</div>
</div>
</div>
<div class="show_box_item">
<div class="short_item_time">详细地址信息</div>
<div class="choose_box" @tap="handlegotoaddresspage">
<div class="con_content_address">{{ showaddressName }}</div>
<div class="loaction_icon">
<img src="../../static/images/locationYellow.png" alt="">
</div>
</div>
</div>
<div class="show_box_item">
<div class="short_item_time">更换车辆</div>
<div class="choose_box">
<CarNoSelecter v-model="showCarNo" :localdata="carOptions" @change="carChoose" placeholder="车辆信息">
</CarNoSelecter>
</div>
</div>
<div>
<time-popup :showbottomstates="showtimebottomstates" @selfclose="handleclosetimebottom"
:timelists="orderServiceTimeList.info" @uploadtime="handleuploadtime"></time-popup>
</div>
</div>
<div class="bottom_safe_area"> </div>
<nut-safe-area position="bottom"></nut-safe-area>
<div class="shopcar_box">
<button class="submit-btn" :style="{ backgroundColor: '#FFCD35' }" @click="handleSubmit">
确认
</button>
<div class="shopcar_box_list">
</div>
<nut-safe-area position="bottom"></nut-safe-area>
</div>
</template>
<script setup>
import {
ref,
reactive
} from 'vue';
import timePopup from '../../components/timepopup'
import CarNoSelecter from '../../components/carNoSelecter'
import {
orderCar,
orderDispatch
} from '../../api/orders'
import {
isDateTimeGreaterThanCurrent
} from '../../utils/date'
import {
carList
} from '../../api/cars.js'
import {
useUserInfo
} from '@/store'
const userInfo = useUserInfo()
const showtimeboxinfo = ref('请选择您预约的洗护时间段')
const timeboxinfoList = ref([])
const showtimebottomstates = ref(false)
const showaddressName = ref('请设置服务地址')
const showCarNo = ref('请选择您的车辆')
const showCarNoItem = ref({})
const chooseUid = ref(0)
const showProjectServerTime = ref('请输入服务时间')
const orderServiceTimeList = reactive({
info: []
})
const carOptions = ref([])
const orderItem = ref({})
const submitList = reactive({
info: {
petGoodsInfos: [],
serviceTime: "",
serviceAddrId: 0
}
})
const fieldNames = ref({
text: "addr",
value: "id",
});
function handleSubmit() {
const submitParams = {
"carId": showCarNo.value,
"orderId":orderItem.value.orderId,
"orderUpdateDTO": {
"addr": showaddressName.value,
"carId": showCarNo.value,
"orderId":orderItem.value.orderId,
"projectionServiceTime": showProjectServerTime.value,
"remark": orderItem.value.remark,
"serviceTime": showtimeboxinfo.value,
"userServiceAddrId":orderItem.value.userServiceAddrId
}
}
console.log(submitParams,'==========submitParams')
orderDispatch(submitParams).then(res => {
if (res.code == 200) {
uni.showToast({
title: '派单成功',
icon: 'success',
duration: 2000
})
// 返回上一页或刷新数据
setTimeout(() => {
// uni.navigateBack()
uni.switchTab({
url: `/pages/index/index`
})
}, 1500)
} else {
uni.showToast({
title: '派单失败,请稍后重试',
icon: 'success',
duration: 2000
})
}
})
}
//车辆选择
function carChoose(val) {
showCarNo.value = val.value
showCarNoItem.value = val
}
function handleuploadtime(e) {
console.log(e, 'handleuploadtime')
showtimeboxinfo.value = e
}
// // 时间处理函数
function getorderServiceTime() {
carList(userInfo.getUid).then((res) => {
if (res.code == 200) {
orderServiceTimeList.info = []
orderServiceTimeList.info.length = 0
let j = 1
for (let item of res.data) {
console.log('------', item)
let date = new Date(item?.serviceDate).getDay()
let result = {
backtime: item?.serviceDate,
date,
ischeck: j == 1 ? true : false,
day: item?.serviceDate?.split('-')[1] + '.' + item?.serviceDate.split('-')[2],
timelist: item?.carDispatchList[0].dispatchResults
}
j += 1
for (let j in result.timelist) {
result.timelist[j].ischeck = false
result.timelist[j].isOver = isDateTimeGreaterThanCurrent(item?.serviceDate, result
.timelist[j].time) //
}
orderServiceTimeList.info.push(result)
}
console.log(orderServiceTimeList, 'res.data.times')
}
})
}
function handleclosetimebottom(e) {
showtimebottomstates.value = e
}
function handlegotoaddresspage() {
uni.navigateTo({
url: '/pages/addresslist/index?type=2'+'&uid='+chooseUid.value,
})
}
function handleshowtimepopup() {
console.log(showtimebottomstates.value)
showtimebottomstates.value = !showtimebottomstates.value
}
onShow(_ => {
uni.$on('returnData', (e) => {
showaddressName.value = e.e.addr
console.log(e)
})
})
onLoad((e) => {
if (e.orderInfo && e.orderInfo != 'undefined') {
const res = JSON.parse(e.orderInfo)
orderItem.value = res
showtimeboxinfo.value = res.serviceTime
showaddressName.value = res.addr
showProjectServerTime.value = res?.projectionServiceTime ? res.projectionServiceTime:0
chooseUid.value = res.uid
getorderServiceTime()
usetCarList()
orderGoodsList(res)
console.log(res);
}
})
function orderGoodsList(data) {
let petLists = data?.petList
if (petLists?.length<=0 )return;
const result = petLists.map(pet => {
// 使用对象展开运算符保留所有原有属性
return {
...pet,
// 添加新的 goodsNameList 属性
goodsNameList: pet.petDetailList
.map(detail => detail.goodsName)
.join(', ')
};
});
orderItem.value.petList = result
console.log(orderItem.value, ">>>>>>n===")
}
//提交编辑信息
function usetCarList() {
orderCar(userInfo.uid).then(res => {
if (res.code == 200) {
const newCarList = res.data.map(car => ({
...car, // 保留原有所有属性
text: car.carNo, // 添加text字段,值为carNo
value: car.id // 添加value字段,值为id
}));
carOptions.value = newCarList
showCarNo.value = newCarList.find(car => car.carNo == orderItem.value.carNo)?.id
}
})
}
function extractPhoneNumber(str) {
if (str?.length <= 0) return ""
// 尝试多种可能的格式
const patterns = [
/联系电话[::]\s*(\d{11})/, // 格式:联系电话:13912712777
/电话[::]\s*(\d{11})/, // 格式:电话:13912712777
/手机[::]\s*(\d{11})/, // 格式:手机:13912712777
/1[3-9]\d{9}/ // 直接匹配11位手机号
];
// for (const pattern of patterns) {
// const match = str.match(pattern);
// if (match) {
// // 返回第一个捕获组或整个匹配
// return match[1] || match[0];
// }
// }
return ""; // 没有找到手机号
}
</script>
<style lang="scss">
image {
height: 100%;
width: 100%;
}
.shop_page_container {
// --nut-navbar-background: #FFDE5E;
--nut-button-border-radius: 0px 25px 25px 0px;
--nut-navbar-color: #312D22;
--nut-button-default-color: #312D22;
--nut-radio-button-border-radius: 8rpx;
--nut-form-item-label-width: 50rpx;
--nut-navbar-box-shadow: 0px 0px 0px 0px;
--nut-textarea-font: 16pt;
--nut-input-border-bottom:rgba(0,0,0,0);
height: 100%;
background-color: #F3F3F3;
}
.show_box {
background-color: #FFFFFF;
border-radius: 16rpx 16rpx 0rpx 0rpx;
}
.show_box_item {
padding: 24rpx;
padding-bottom: 0rpx;
box-sizing: border-box;
}
.choose_box {
display: flex;
flex-flow: row nowrap;
align-items: center;
margin-top: 12rpx;
width: 702rpx;
height: 112rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 2rpx solid #E5E4E4;
color: $uni-text-color-grey;
font-size: $uni-font-size-base;
padding: 24rpx;
box-sizing: border-box;
}
.bottom_safe_area {
height: 128rpx;
padding-bottom: 60rpx;
}
.short_item_time {
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
max-width: 500rpx;
margin-top: 20rpx;
// text-align: right;
}
.short_item_normal {
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
max-width: 650rpx;
margin-top: 20rpx;
// text-align: right;
}
.shopcar_box {
position: fixed;
bottom: 0px;
left: 0px;
background-color: #fff;
.shopcar_box_list {
height: 68rpx;
width: 750rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: 20rpx;
box-sizing: border-box;
.box_list_button {
width: 702rpx;
height: 88rpx;
background: linear-gradient(270deg, #FFCD35 0%, #FFDE5E 100%);
border-radius: 74rpx 74rpx 74rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
color: $uni-text-color;
}
}
}
.con_content {
color: #444137;
font-size: 13pt;
}
.con_content_address {
color: #444137;
font-size: 13pt;
white-space: nowrap;
/* 禁止换行 */
overflow: hidden;
/* 隐藏超出部分 */
text-overflow: ellipsis;
/* 超出部分显示省略号 */
// width: 500px; /* 设置一个固定宽度或最大宽度 */
}
.submit-btn {
// margin-top: 50rpx;
height: 88rpx;
width: 700rpx;
line-height: 88rpx;
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
background-color: #cccccc;
transition: background-color 0.3s;
justify-content: space-between;
}
.base_box {
width: 702rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 24rpx;
box-sizing: border-box;
margin: 24rpx;
}
.short_box {
padding-bottom: 0rpx;
background-color: #FFFFFF;
.short_item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
margin-bottom: 26rpx;
padding: 24rpx;
.short_item_title {
color: $uni-text-color;
font-size: $uni-font-size-base;
font-weight: 500;
}
.short_item_time {
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
max-width: 500rpx;
text-align: right;
}
.short_item_pay {
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
max-width: 500rpx;
text-align: right;
color: red;
}
}
}
.short_box::after {
content: '';
display: table;
}
.loaction_icon {
position: absolute;
right: 44rpx;
width: 32rpx;
height: 40rpx;
}
.choose_box_text {
display: flex;
flex-flow: row nowrap;
align-items: center;
margin-top: 12rpx;
width: 702rpx;
height: 112rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 2rpx solid #E5E4E4;
color: $uni-text-color-grey;
font-size: $uni-font-size-base;
box-sizing: border-box;
}
</style>
+466
View File
@@ -0,0 +1,466 @@
<template>
<div class="shop_page_container">
<nut-navbar title="订单编辑" :fixed="true" ref="navtest" left-show :safe-area-inset-top="true"
:custom-color="'#312D22'">
</nut-navbar>
<div class="show_box_item">
<div class="short_item_time">修改服务时间</div>
<div class="choose_box" @tap="handleshowtimepopup">
<div class="con_content">{{ showtimeboxinfo }}</div>
</div>
</div>
<div class="show_box_item">
<div class="short_item_time">修改服务地址</div>
<div class="choose_box" @tap="handlegotoaddresspage">
<div class="con_content_address">{{ showaddressName }}</div>
<div class="loaction_icon">
<img src="../../static/images/locationYellow.png" alt="">
</div>
</div>
</div>
<div class="show_box_item">
<div class="short_item_time">更换车辆</div>
<div class="choose_box">
<!-- <div class="con_content">{{ showCarNo }}</div> -->
<CarNoSelecter v-model="showCarNo" :localdata="carOptions" @change="carChoose" placeholder="车辆信息">
</CarNoSelecter>
</div>
</div>
<div class="show_box_item">
<div class="short_item_time">备注</div>
<div class="choose_box_text">
<nut-textarea placeholder="请输入备注信息" v-model="orderRemark" autosize />
</div>
</div>
<div>
<time-popup :showbottomstates="showtimebottomstates" @selfclose="handleclosetimebottom"
:timelists="orderServiceTimeList.info" @uploadtime="handleuploadtime"></time-popup>
</div>
</div>
<div class="bottom_safe_area"> </div>
<nut-safe-area position="bottom"></nut-safe-area>
<div class="shopcar_box">
<button class="submit-btn" :style="{ backgroundColor: '#FFCD35' }" @click="handleSubmit">
确认
</button>
<div class="shopcar_box_list">
</div>
<nut-safe-area position="bottom"></nut-safe-area>
</div>
</template>
<script setup>
import {
ref,
reactive
} from 'vue';
import timePopup from '../../components/timepopup'
import CarNoSelecter from '../../components/carNoSelecter'
import {
orderCar,
orderUpdate
} from '../../api/orders'
import {
isDateTimeGreaterThanCurrent
} from '../../utils/date'
import {
carList
} from '../../api/cars.js'
const phoneNum = ref('')
import {
useSystemInfo,
useUserInfo
} from '@/store'
const userInfo = useUserInfo()
const showtimeboxinfo = ref('请选择您预约的洗护时间段')
const timeboxinfoList = ref([])
const showtimebottomstates = ref(false)
const showaddressName = ref('请设置服务地址')
const addressList = ref([])
const typeShow = ref(false)
const showCarNo = ref('请选择您的车辆')
const showCarNoItem = ref({})
const carNoList = ref([])
const orderRemark = ref('')
const chooseUid = ref(0)
const orderServiceTimeList = reactive({
info: []
})
const carOptions = ref([])
const orderItem = ref({})
const submitList = reactive({
info: {
petGoodsInfos: [],
serviceTime: "",
serviceAddrId: 0
}
})
function handleSubmit() {
//orderItem.value.userServiceAddrId
const submitParams = {
"addr": showaddressName.value,
"carId": showCarNo.value,
"orderId": orderItem.value?.orderId,
"projectionServiceTime": orderItem.value.projectionServiceTime,
"remark": orderRemark.value || '',
"serviceTime": showtimeboxinfo.value,
"userServiceAddrId": orderItem.value.userServiceAddrId
}
orderUpdate(submitParams).then(res => {
if (res.code == 200) {
uni.showToast({
title: '编辑成功',
icon: 'success',
duration: 2000
})
// 返回上一页或刷新数据
setTimeout(() => {
// uni.navigateBack()
uni.switchTab({
url: `/pages/index/index`
})
}, 1500)
} else {
uni.showToast({
title: '编辑失败,请稍后重试',
icon: 'success',
duration: 2000
})
}
})
}
//车辆选择确认
function onCarConfirm() {
}
//车辆选择
function carChoose(val) {
showCarNo.value = val.value
showCarNoItem.value = val
}
function handleuploadtime(e) {
console.log(e, 'handleuploadtime')
showtimeboxinfo.value = e
}
// // 时间处理函数
function getorderServiceTime() {
carList(userInfo.getUid).then((res) => {
if (res.code == 200) {
console.log('------', res)
orderServiceTimeList.info = []
orderServiceTimeList.info.length = 0
let j = 1
for (let item of res?.data) {
console.log('------', item)
let date = new Date(item?.serviceDate).getDay()
let result = {
backtime: item?.serviceDate,
date,
ischeck: j == 1 ? true : false,
day: item?.serviceDate?.split('-')[1] + '.' + item?.serviceDate?.split('-')[2],
timelist: item?.carDispatchList?.[0]?.dispatchResults || []
}
j += 1
for (let j in result.timelist) {
result.timelist[j].ischeck = false
result.timelist[j].isOver = isDateTimeGreaterThanCurrent(item?.serviceDate, result
.timelist[j].time) //
}
orderServiceTimeList.info.push(result)
}
console.log(orderServiceTimeList, 'res.data.times')
}
})
}
function handleclosetimebottom(e) {
showtimebottomstates.value = e
}
function handlegotoaddresspage() {
uni.navigateTo({
url: '/pages/addresslist/index?type=2' + '&uid=' + chooseUid.value,
})
}
function handleshowtimepopup() {
console.log(showtimebottomstates.value)
showtimebottomstates.value = !showtimebottomstates.value
}
onShow(_ => {
uni.$on('returnData', (e) => {
showaddressName.value = e.e.addr
console.log(e)
})
})
onLoad((e) => {
console.log(JSON.parse(e.orderInfo), '===========onLoad')
if (e.orderInfo && e.orderInfo != 'undefined') {
const res = JSON.parse(e.orderInfo)
orderItem.value = res
showtimeboxinfo.value = res.serviceTime
showaddressName.value = res.addr
orderRemark.value = res.remark
chooseUid.value = res.uid
getorderServiceTime()
usetCarList()
console.log(res);
}
})
//提交编辑信息
function usetCarList() {
orderCar(userInfo.uid).then(res => {
if (res.code == 200) {
const newCarList = res.data.map(car => ({
...car, // 保留原有所有属性
text: car.carNo, // 添加text字段,值为carNo
value: car.id // 添加value字段,值为id
}));
carOptions.value = newCarList
showCarNo.value = newCarList.find(car => car.carNo == orderItem.value.carNo)?.id
}
})
}
</script>
<style lang="scss">
image {
height: 100%;
width: 100%;
}
.shop_page_container {
// --nut-navbar-background: #FFDE5E;
--nut-button-border-radius: 0px 25px 25px 0px;
--nut-navbar-color: #312D22;
--nut-button-default-color: #312D22;
--nut-radio-button-border-radius: 8rpx;
--nut-form-item-label-width: 50rpx;
--nut-navbar-box-shadow: 0px 0px 0px 0px;
--nut-textarea-font: 16pt // background: $uni-color-primary;
height: 100%;
}
.show_box {
background-color: #FFFFFF;
border-radius: 16rpx 16rpx 0rpx 0rpx;
}
.show_box_item {
padding: 24rpx;
padding-bottom: 0rpx;
box-sizing: border-box;
}
.show_scroll_list {
max-height: 385rpx;
margin-top: 26rpx;
box-sizing: border-box;
}
.show_item_box {
// height: 100%;
max-height: 385rpx;
display: flex;
flex-flow: column wrap;
align-content: start;
}
.twoboxclass {
flex-flow: row nowrap;
}
.choose_box {
display: flex;
flex-flow: row nowrap;
align-items: center;
margin-top: 12rpx;
width: 702rpx;
height: 112rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 2rpx solid #E5E4E4;
color: $uni-text-color-grey;
font-size: $uni-font-size-base;
padding: 24rpx;
box-sizing: border-box;
}
.choose_box_text {
display: flex;
flex-flow: row nowrap;
align-items: center;
margin-top: 12rpx;
width: 702rpx;
height: 112rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 2rpx solid #E5E4E4;
color: $uni-text-color-grey;
font-size: $uni-font-size-base;
box-sizing: border-box;
}
.choose_box_icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.bottom_safe_area {
height: 128rpx;
}
.shopcar_box_list {
height: 128rpx;
width: 750rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: 20rpx;
box-sizing: border-box;
}
.shopcar_small_box {
display: flex;
flex-flow: column nowrap;
align-items: center;
}
.small_icon_box {
margin-top: 4rpx;
height: 48rpx;
width: 48rpx;
}
.small_box_text {
color: $uni-text-color-grey;
font-size: $uni-font-size-sm;
}
.shopcar_large_box {
font-size: $uni-font-size-base;
color: $uni-text-color;
font-weight: 500;
display: flex;
flex-flow: row nowrap;
}
.addcar {
width: 208rpx;
height: 88rpx;
// background-color: #FFDE5E;
border-radius: 74rpx 0rpx 0rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
}
.buynow {
width: 208rpx;
height: 88rpx;
background-color: #FFCD35;
border-radius: 0rpx 74rpx 74rpx 0rpx;
display: flex;
justify-content: center;
align-items: center;
}
.short_item_time {
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
max-width: 500rpx;
margin-top: 20rpx;
// text-align: right;
}
.shopcar_box {
position: fixed;
bottom: 0px;
left: 0px;
background-color: #fff;
.shopcar_box_list {
height: 128rpx;
width: 750rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: 20rpx;
box-sizing: border-box;
.box_list_button {
width: 702rpx;
height: 88rpx;
background: linear-gradient(270deg, #FFCD35 0%, #FFDE5E 100%);
border-radius: 74rpx 74rpx 74rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
color: $uni-text-color;
}
}
}
.con_content {
color: #444137;
font-size: 13pt;
}
.con_content_address {
color: #444137;
font-size: 12pt;
white-space: nowrap;
/* 禁止换行 */
overflow: hidden;
/* 隐藏超出部分 */
text-overflow: ellipsis;
/* 超出部分显示省略号 */
max-width: 94%;
}
.submit-btn {
height: 88rpx;
width: 700rpx;
line-height: 88rpx;
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
background-color: #cccccc;
transition: background-color 0.3s;
justify-content: space-between;
}
.loaction_icon {
position: absolute;
right: 44rpx;
width: 32rpx;
height: 40rpx;
}
</style>
+468
View File
@@ -0,0 +1,468 @@
<template>
<div class="order_info">
<nut-navbar title="订单详情" :fixed="true" ref="navtest" left-show :safe-area-inset-top="true"
:custom-color="'#312D22'">
</nut-navbar>
<div class="order_info_container">
<!-- 宠物列表 -->
<div class="base_box height_box" v-for="(item, index) in petList" :key="index">
<div class="top_box">
<div class="top_icon">
<img :src="item && item?.headImgUrl || defalitImg" alt="" class="icon_img" srcset="">
</div>
<div class="top_title">
<div class="title_top">
<header-box :title="item?.nickName" :sub="getTypeItem(orderDel.orderStatus)"
:type="'yellow'"></header-box>
<div class="info_price title_top_info" @tap="handleCleanList(item.petId)">
洗护记录
</div>
</div>
<div class="title_content">
<div class="item">
<Gender :gender="item?.gender"></Gender>
</div>
<div class="item">
{{ item?.petBaseInfo?.hair == 1 ? '长毛' : '短毛' }}
</div>
<div>
{{ calculateAgeShow(item?.birthday) || '--' }}
</div>
</div>
</div>
</div>
<div class="top_title" style="margin-top: 20rpx;padding-bottom: 40rpx;">
<div class="top_title" style="color: #8C887C;">
体重:{{ item?.weight }}
</div>
<div class="title_content" style="color: #8C887C; margin-top: 16rpx;">
洗护时长:{{ orderItem?.projectionServiceTime ||0}}分钟
</div>
</div>
<div v-for="(goods, index1) in item.petDetailList" :key="index1">
<div style=" display: flex;align-content: center; justify-content: space-between; padding-bottom: 16rpx;font-size: 14pt;color: #444137;">
<div class="info_title">
{{ goods.goodsName }}
</div>
<div class="info_price" :class="{ yellow_info: goods.isyellow, isline: goods.isline }">
{{ '¥' + goods.amount }}
</div>
</div>
</div>
</div>
<div class="order_pay_info" >
<div class="pay_info_item" v-for="(goods, index1) in item?.goods" :key="index1"
:class="{ couponList_item: goods?.iscouponList }">
<div class="info_title">
{{ goods?.name }}
</div>
<div class="info_price" v-if="goods?.isdiscount"
:class="{ yellow_info: goods?.isyellow, isline: goods?.isline }">
{{ goods?.price / 10 }}折
</div>
<div class="info_price" v-if="!goods?.isdiscount"
:class="{ yellow_info: goods?.isyellow, isline: goods?.isline }">
{{ goods?.iscouponList ? goods?.price : '¥' + goods?.price }}
</div>
</div>
</div>
<div class="base_box short_box" style="padding-bottom: 40rpx;">
<div class="top_title title_bottom ">
<div class="info_price">总金额</div>
<div class="title_content" style="color: #8C887C;">{{ '¥' + orderItem?.amount }}</div>
</div>
<div class="top_title title_bottom">
<div class="info_price">支付金额</div>
<div class="yellow_info" style="color: #FFCD35;">{{ '¥' + orderItem?.payAmount }}</div>
</div>
<div class="top_title title_bottom">
<div class="info_price">会员折扣金额</div>
<div class="short_item_title" style="color: #8C887C;">{{ '¥' + orderItem?.vipDiscountAmount }}</div>
</div>
<div class="top_title title_bottom">
<div class="info_price">优惠券折扣金额</div>
<div class="short_item_title" style="color: #8C887C;">{{ '¥' + orderItem?.couponDiscountAmount }}
</div>
</div>
<div class="top_title title_bottom">
<div class="info_price">优惠券ID</div>
<div class="short_item_title" style="color: #8C887C;">{{ "--" }}</div>
</div>
<div class="top_title title_bottom">
<div class="info_price">总洗护时长</div>
<div class="short_item_title" style="color: #8C887C;">{{ orderItem?.projectionServiceTime + '分钟' }}
</div>
</div>
</div>
<div class="base_box short_box">
<div class="short_item" >
<div class="short_item_time">预约时间</div>
<div class="short_item_title" style="padding-top: 16rpx;font-size: 13pt;">{{ orderItem.serviceTime }}</div>
</div>
<div class="short_item">
<div class="short_item_time">下单时间</div>
<div class="short_item_title" style="padding-top: 16rpx;font-size: 13pt;">{{ orderItem.createTime }}</div>
</div>
<div class="short_item">
<div class="short_item_time">联系方式</div>
<div class="short_item_title" style="padding-top: 16rpx;font-size: 13pt;">{{ extractPhoneNumber(orderItem.userServiceAddr) }}</div>
</div>
<div class="short_item">
<div class="short_item_time">服务地址</div>
<div class="short_item_title" style="padding-top: 16rpx;font-size: 13pt;">{{ orderItem.addr }}</div>
</div>
</div>
</div>
<div class="bottom_safe_area"> </div>
<nut-safe-area position="bottom"></nut-safe-area>
<div class="shopcar_box" v-if="orderItem?.dispatchStatus!='1' ||orderItem?.dispatchStatus!=1">
<view class="button_box">
<view class="item_button">
<div @tap.stop="handleUpdate(0, orderItem?.id)">取消订单</div>
</view>
<view class="item_button" v-if="orderItem?.dispatchStatus=='0' ||orderItem?.dispatchStatus==0">
<div @tap.stop="handleUpdate(1, pet?.id)">派单</div>
</view>
<view class="item_button" v-if="orderItem?.dispatchStatus=='1' ||orderItem?.dispatchStatus==1">
<div>已派单</div>
</view>
<view class="item_button">
<div @tap="handleUpdate(2, pet?.id)">编辑</div>
</view>
</view>
<div class="shopcar_box_list">
</div>
<nut-safe-area position="bottom"></nut-safe-area>
</div>
</div>
</template>
<script setup>
import headerBox from '../../components/headerBox'
import {
orderCancel,
orderDispatch
} from '../../api/orders'
import {
getTypeItem
} from '../../utils/index'
import Gender from '../../components/gender'
import {
ref
} from 'vue'
const defalitImg = ref('../../static/images/catgroup.png')
const components = {
'Gender': Gender,
};
import {
dateExportFormat,
calculateAge
} from '../../utils/date.js'
const petList = ref([])
const orderItem = ref({})
const orderDel = ref({}) //已完成
onLoad((e) => {
if (e.orderInfo && e.orderInfo != 'undefined') {
const res = JSON.parse(e.orderInfo)
petList.value = res.petList
orderItem.value = res
console.log(res);
}
})
//洗护记录跳转
function handleCleanList(id) {
uni.navigateTo({
url: '/pages/careorderinfoCleanList/index?id=' + id
})
}
//事件跳转
function handleUpdate(type, id) {
if (type == 0) { //订单取消
handOrderCancle(id)
} else if (type == 1) { //派单
uni.navigateTo({
url: '/pages/orderDispatch/index?orderInfo=' + JSON.stringify(orderItem.value)
})
} else { //编辑
uni.navigateTo({
url: '/pages/orderEdit/index?orderInfo=' + JSON.stringify(orderItem.value)
})
}
}
//取消订单
function handOrderCancle(id) {
orderCancel(id).then(res => {
if (res.code == 200) {
uni.showToast({
title: '取消成功',
icon: 'success',
duration: 2000
})
// 返回上一页或刷新数据
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
uni.showToast({
title: '取消失败,请重试',
icon: 'none'
})
}
})
}
function calculateAgeShow(age) {
return age != undefined ? calculateAge(age) : '---'
}
function extractPhoneNumber(str) {
if (str?.length <= 0) return ""
// 尝试多种可能的格式
const patterns = [
/联系电话[::]\s*(\d{11})/, // 格式:联系电话:13912712777
/电话[::]\s*(\d{11})/, // 格式:电话:13912712777
/手机[::]\s*(\d{11})/, // 格式:手机:13912712777
/1[3-9]\d{9}/ // 直接匹配11位手机号
];
for (const pattern of patterns) {
const match = str?.match(pattern);
if (match) {
// 返回第一个捕获组或整个匹配
return match[1] || match[0];
}
}
return ""; // 没有找到手机号
}
</script>
<style lang="scss">
page {
--nut-navbar-background: #F3F3F3;
--nut-navbar-color: #312D22;
height: 100%;
}
.order_info {
height: 100%;
background: #F3F3F3;
.order_info_container {
padding: 24rpx;
box-sizing: border-box;
.base_box {
width: 702rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 24rpx;
box-sizing: border-box;
margin-bottom: 24rpx;
}
.height_box {
.top_box {
display: flex;
flex-flow: row nowrap;
.top_icon {
width: 96rpx;
height: 96rpx;
margin-right: 16rpx;
border-radius: 50%;
.icon_img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.top_title {
.title_top {
width: 542rpx;
margin-bottom: 12rpx;
display: flex;
justify-content: space-between;
}
.title_content {
display: flex;
flex-flow: row nowrap;
justify-content: left;
align-items: center;
color: $uni-text-color-grey;
font-size: $uni-font-size-base;
.item {
margin-right: 10rpx;
}
}
}
}
.order_pay_info {
margin-top: 16rpx;
margin-bottom: 16rpx;
.pay_info_item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
margin-top: 26rpx;
margin-bottom: 26rpx;
.info_title {
color: $uni-text-color;
font-size: $uni-font-size-base;
}
.info_price {
color: $uni-text-color;
font-size: $uni-font-size-base;
padding-top: 8rpx;
padding-bottom: 8rpx;
}
.yellow_info {
color: #FFCD35
}
}
.couponList_item {
width: 654rpx;
height: 64rpx;
border-radius: 8rpx;
background: #F6F6F6;
padding: 10rpx 24rpx;
box-sizing: border-box;
}
}
}
.short_box {
// height: 272rpx;
padding-bottom: 0rpx;
.short_item {
display: flex;
flex-flow: column;
margin-bottom: 26rpx;
padding-bottom: 20rpx;
border-bottom: 1px solid #E9E8E8;
.short_item_title {
color: $uni-text-color;
font-size: $uni-font-size-base;
font-weight: 500;
}
.short_item_time {
font-size: $uni-font-size-base;
color: $uni-text-color-grey;
max-width: 500rpx;
// text-align: right;
}
}
}
.short_box::after {
content: '';
display: table;
}
}
}
.isline {
text-decoration: line-through
}
.title_top_info {
border-bottom: 1px solid #333;
}
.title_bottom {
justify-content: space-between;
display: flex;
padding-top: 30rpx;
font-size: 16px;
}
.button_box {
width: 90%;
height: 100rpx;
position: absolute;
display: flex;
align-content: center;
justify-content: space-between;
left: 40rpx;
padding-bottom: 80rpx;
.item_button {
// margin-left: 44rpx;
width: 176rpx;
height: 60rpx;
border-radius: 200rpx 200rpx 200rpx 200rpx;
border: 2rpx solid #BCB9AE;
text-align: center;
line-height: 60rpx;
color: #312D22;
}
.item_button_color {
background-color: #FFCF38;
border: 0rpx solid #BCB9AE;
}
}
.price_row {}
.shopcar_box {
position: fixed;
bottom: 0px;
left: 0px;
background-color: #fff;
.shopcar_box_list {
height: 128rpx;
width: 750rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: 20rpx;
box-sizing: border-box;
.box_list_button {
width: 702rpx;
height: 88rpx;
background: linear-gradient(270deg, #FFCD35 0%, #FFDE5E 100%);
border-radius: 74rpx 74rpx 74rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
color: $uni-text-color;
}
}
}
.bottom_safe_area {
height: 128rpx;
}
</style>
+393
View File
@@ -0,0 +1,393 @@
<template>
<view class="pet_container">
<div class="pet_list">
<nut-navbar title="我的宠物" :fixed="true" ref="navtest" left-show :safe-area-inset-top="true"
:custom-color="'#312D22'">
</nut-navbar>
<div class="list_box" v-for="pet in petLists">
<div class="list_item" :key="pet?.id">
<div class="list_item_top">
<div class="list_item_header">
<img :src="pet?.headImgUrl!='' ? pet?.headImgUrl : defalitImg" alt="" srcset=""
class="img_icon">
</div>
<div class="list_item_right">
<div class="list_content">
<div class="title_top">
<div class="con_title">{{ pet?.nickName }}</div>
<div class="info_price title_top_info" @tap="handleCleanList(pet?.petId)">
洗护记录
</div>
</div>
<div class="con_content">
<Gender :gender="pet?.gender"></Gender>
<div class="con_sub">{{ pet?.petBaseInfo?.hair==1?'长毛':"短毛"}}{{ pet?.petBaseInfo?.petType==1?'猫':"狗"}}</div>
<div class="con_sub">{{calculateAgeShow(pet?.birthday)||'--'}}</div>
</div>
<div class="con_content">
<div class="con_sub_time">上次洗护时间:{{ pet?.lastServiceDate }}</div>
</div>
</div>
</div>
</div>
<!-- <view class="button_box" >
<view class="item_button" >
<div @tap.stop="handleUpdate(0,pet?.id)">编辑</div>
</view>
<view class="item_button">
<div @tap.stop="handleUpdate(1,pet?.id)">删除</div>
</view>
<view class="item_button item_button_color">
<div @tap="handleUpdate(2,pet?.id)">去下单</div>
</view>
</view> -->
</div>
</div>
<div class="petlist_bottom_box"></div>
<nut-safe-area position="bottom"></nut-safe-area>
</div>
<div class="no-data" v-if="petLists?.length==0">
<div class="content">
<img src="../../static/images/petdefault.png" alt="" class="no-img">
<div class="msg">暂无数据</div>
</div>
</div>
</view>
</template>
<script setup>
import {
onShow
} from '@dcloudio/uni-app';
import Gender from '../../components/gender'
import moment from 'moment';
import {
useSystemInfo,
useUserInfo
} from '@/store'
import {
dateExportFormat,
calculateAge
} from '../../utils/date.js'
import {orderUpdate ,orderCancel} from '../../api/orders.js'
const systemInfo = useSystemInfo()
const userInfo = useUserInfo()
const components = {
'Gender': Gender,
};
const defalitImg = ref('../../static/images/catgroup.png')
const petLists = ref([])
const orderPet = ref({})
function petDetail(id) {
uni.navigateTo({
url: id ? `/pages/cleaningItem/index?id=${id}` : '/pages/petpage/index'
})
}
function init() {
uni.showLoading({
title: '加载中'
})
blindDateListOwn(userInfo.getUid).then(res => {
uni.hideLoading()
if (res.code === 200) {
petLists.value = res.data
}
})
}
onShow((e) => {
// init()
})
onLoad((e) => {
orderPet.value = JSON.parse(e.list)
petLists.value = orderPet.value.petList
})
//宠物详情
// function handleBlindDateItem(id) {
// uni.navigateTo({
// url: `/pages/blindDatePetListUserItem/index?id=${id}`
// })
// }
//编辑,删除,去下单
function handleUpdate(type,id){
if(type==0){ //编辑
}else if(type ==1){ //删除
deleteOrder(id)
}else { //去下单
}
}
//订单删除调用
function deleteOrder(id) {
uni.showModal({
title: '提示',
content: '您确认要删除吗?',
confirmColor: '#FFCD35',
success: function(res) {
if (res.confirm) {
orderCancel({id}).then(res => {
if (res.code == 200) {
uni.showToast({
title: '删除成功',
//将值设置为 success 或者直接不用写icon这个参数
icon: 'success',
//显示持续时间为 2秒
duration: 2000
})
init()
}
})
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
}
function calculateAgeShow(age) {
return age != undefined ? calculateAge(age) : '---'
}
//洗护记录
function handleCleanList(id) {
console.log('id-------', id)
uni.navigateTo({
url: '/pages/careorderinfoCleanList/index?id=' + id
})
}
</script>
<style lang="scss">
// .nut-button--default {
// border: 2rpx solid #312D22 !important;
// }
.pet_container {
background-color: #F3F3F3;
min-height: 100vh;
box-sizing: border-box;
}
.pet_list {
background: #F3F3F3;
min-height: 100%;
--nut-navbar-background: #F3F3F3;
--nut-navbar-color: #312D22;
--nut-button-default-height: 60rpx;
--nut-button-default-color: #312D22;
--nut-button-default-bg-color: #fff;
--nut-button-primary-color: #312D22;
.list_box {
padding: 24rpx;
box-sizing: border-box;
.list_item {
width: 702rpx;
height: 220rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding-left: 24rpx;
padding-right: 24rpx;
box-sizing: border-box;
display: flex;
flex-flow: row nowrap;
position: relative;
align-content: center;
justify-content: center;
// align-items: center;
.list_item_top{
width: 702rpx;
height: 220rpx;
display: flex;
flex-flow: row nowrap;
}
.list_item_header {
height: 100rpx;
width: 100rpx;
border-radius: 50%;
margin-top: 30rpx;
.img_icon {
background-color: #FFCD35;
width: 96rpx;
height: 96rpx;
border-radius: 50%;
}
}
.list_item_right {
height: 100%;
width: 100%;
flex-flow: column nowrap;
display: flex;
align-content: center;
}
.list_content {
margin-left: 16rpx;
width: 100%;
padding-top: 24rpx;
.con_title {
font-size: $uni-font-size-title;
color: $uni-text-color;
margin-bottom: 10rpx;
}
.con_content {
display: flex;
align-items: center;
margin-bottom: 24rpx;
}
.con_sub {
font-size: $uni-font-size-base;
margin-left: 20rpx;
color: $uni-text-color-placeholder;
}
.con_sub_time {
font-size: $uni-font-size-base;
color: #444137;
}
.con_con {
color: $uni-text-color;
font-size: $uni-font-size-base;
margin-bottom: 22rpx;
}
}
.con_times {
margin-left: 16rpx;
display: flex;
.con_number {
font-size: $uni-font-size-base;
color: $uni-text-color;
margin-bottom: 10rpx;
}
}
}
}
}
.petlist_bottom_box {
height: 128rpx;
background-color: #F3F3F3;
}
.shopcar_box {
position: fixed;
bottom: 0px;
left: 0px;
background-color: #F3F3F3;
.shopcar_box_list {
height: 128rpx;
width: 750rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: 20rpx;
box-sizing: border-box;
.box_list_button {
width: 702rpx;
height: 88rpx;
background: linear-gradient(270deg, #FFCD35 0%, #FFDE5E 100%);
border-radius: 74rpx 74rpx 74rpx 74rpx;
display: flex;
justify-content: center;
align-items: center;
color: $uni-text-color;
}
}
}
.no-data {
width: 100%;
height: 100%;
min-height: 1480rpx;
display: flex;
justify-content: center;
margin-top: 20%;
.content {
text-align: center;
height: 100%;
.msg {
margin: 40rpx;
}
.no-img {
width: 262rpx;
height: 262rpx;
}
}
}
.title_top {
width: 542rpx;
display: flex;
justify-content: space-between;
}
.title_top_info {
border-bottom: 1px solid #565656;
margin-right: 36rpx;
color: #565656;
font-size: 17px;
padding-top: 12rpx;
}
.button_box {
width: 100%;
height: 100rpx;
position: absolute;
left: 8rpx;
bottom: 24rpx;
right: 24rpx;
display: flex;
flex-flow: row nowrap;
align-content: center;
.item_button {
margin-left: 44rpx;
width: 176rpx;
height: 60rpx;
border-radius: 200rpx 200rpx 200rpx 200rpx;
border: 2rpx solid #BCB9AE;
text-align: center;
line-height: 60rpx;
color: #312D22;
}
.item_button_color{
background-color: #FFCF38;
border: 0rpx solid #BCB9AE;
}
}
</style>
+325
View File
@@ -0,0 +1,325 @@
<template>
<div class="order_info">
<nut-navbar title="订单详情" :fixed="true" ref="navtest" left-show :safe-area-inset-top="true"
:custom-color="'#312D22'">
</nut-navbar>
<div class="order_info_container">
<div class="base_box height_box" v-for="(item, index) in orderDel?.petList" :key="index">
<div class="top_box">
<div class="top_icon">
<img :src="item?.headImgUrl || defalitImg" alt="" class="icon_img"
srcset="">
</div>
<div class="top_title">
<div class="title_top">
<header-box :title="item?.nickName"
:sub="getTypeItem(orderDel?.orderStatus)" :type="'yellow'"></header-box>
</div>
<div class="title_content">
<div class="item">
<Gender :gender="item?.gender"></Gender>
</div>
<div class="item">
{{ item?.assortment }}
</div>
<div>
{{ item?.birthday }}
</div>
</div>
</div>
</div>
<div class="base_box short_box">
<div class="order_pay_info">
<div class="pay_info_item" v-for="(goods, index1) in item.petDetailList" :key="index1"
:class="{ couponList_item: goods?.iscouponList }">
<div class="info_title">
{{ goods.goodsName }}
</div>
<div class="info_price" v-if="goods.isdiscount"
:class="{ yellow_info: goods.isyellow, isline: goods.isline }">
{{ goods.price / 10 }}折
</div>
<div class="info_price" v-if="!goods.isdiscount"
:class="{ yellow_info: goods.isyellow, isline: goods.isline }">
{{ goods.iscouponList ? goods.price : '¥' + goods.price }}
</div>
</div>
</div>
</div>
</div>
<div class="base_box short_box">
<div class="short_item">
<div class="short_item_title">预约时间</div>
<div class="short_item_time">{{ orderDel && orderDel.serviceTime }}</div>
</div>
<div class="short_item">
<div class="short_item_title">下单时间</div>
<div class="short_item_time">{{ orderDel && orderDel.createTime }}</div>
</div>
<div class="short_item">
<div class="short_item_title">联系方式</div>
<div class="short_item_time">{{ extractPhoneNumber( orderDel.userServiceAddr) }}</div>
</div>
<div class="short_item">
<div class="short_item_title">服务地址</div>
<div class="short_item_time">{{ orderDel.addr }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import headerBox from '../../components/headerBox'
import {
orderDetail
} from '../../api/orders'
import {
getTypeItem
} from '../../utils/index'
import Gender from '../../components/gender'
import {
ref
} from 'vue'
const defalitImg = ref('../../static/images/catgroup.png')
const components = {
'Gender': Gender,
};
const orderList = ref([])
const orderDel = ref({}) //已完成
onLoad((e) => {
console.log('e================', e);
if (e && e !== 'undefined') {
const res = JSON.parse(e.orderInfo)
orderDel.value = res
console.log('e================', orderDel.value);
// orderDetail( e.id ).then(res => {
// if (res.code === 200) {
// for (let i in res.data.subOrderList) {
// let result = {
// petInfo: {},
// goods: []
// }
// let goods = res.data.subOrderList[i].goods
// result.petInfo = res.data.subOrderList[i].userPetInfo.petInfo
// result.petBaseInfo = res.data.subOrderList[i].userPetInfo.petBaseInfo
// if (goods.length > 0) {
// for (let j in goods) {
// result.goods.push(goods[j])
// }
// }
// if (result.goods.length > 0) {
// if (res.data.subOrderList[i].vipDiscountAmount > 0 || res.data.subOrderList[i]
// .couponDiscountAmount > 0) {
// result.goods.push({
// name: '总计',
// price: res.data.subOrderList[i].amount,
// isline: true
// })
// // result.goods.push({ name: '会员折扣', price: res.data.subOrderList[i].discount, isdiscount: true })
// result.goods.push({
// name: '会员减免',
// price: '-¥' + (parseFloat(res.data.subOrderList[i].vipDiscountAmount))
// .toFixed(1),
// iscouponList: true
// })
// // result.goods.push({ name: '会员折扣', price: res.data.subOrderList[i].discount, isdiscount: true })
// if (res.data.subOrderList[i].coupons) {
// result.goods.push({
// name: res.data.subOrderList[i].coupons.name,
// price: '-¥' + res.data.subOrderList[i].couponDiscountAmount,
// iscouponList: true
// })
// }
// result.goods.push({
// name: '折后价',
// price: res.data.subOrderList[i].payAmount,
// isyellow: true
// })
// } else {
// if (res.data.subOrderList[i].coupons) {
// result.goods.push({
// name: res.data.subOrderList[i].coupons.name,
// price: '-¥' + res.data.subOrderList[i].couponDiscountAmount,
// iscouponList: true
// })
// }
// result.goods.push({
// name: '总计',
// price: res.data.subOrderList[i].payAmount,
// isyellow: true
// })
// }
// }
// orderList.value.push(result)
// }
// console.log(orderList.value)
// orderDel.value = res.data
// }
// })
}
})
function extractPhoneNumber(str) {
// 尝试多种可能的格式
const patterns = [
/联系电话[::]\s*(\d{11})/, // 格式:联系电话:13912712777
/电话[::]\s*(\d{11})/, // 格式:电话:13912712777
/手机[::]\s*(\d{11})/, // 格式:手机:13912712777
/1[3-9]\d{9}/ // 直接匹配11位手机号
];
for (const pattern of patterns) {
const match = str?.match(pattern);
if (match) {
// 返回第一个捕获组或整个匹配
return match[1] || match[0];
}
}
return null; // 没有找到手机号
}
</script>
<style lang="scss">
page {
--nut-navbar-background: #F3F3F3;
--nut-navbar-color: #312D22;
height: 100%;
}
.order_info {
height: 100%;
background: #F3F3F3;
.order_info_container {
padding: 24rpx;
box-sizing: border-box;
.base_box {
width: 702rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 24rpx;
box-sizing: border-box;
margin-bottom: 24rpx;
}
.height_box {
.top_box {
display: flex;
flex-flow: row nowrap;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
.top_icon {
width: 96rpx;
height: 96rpx;
margin-right: 16rpx;
border-radius: 50%;
.icon_img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.top_title {
.title_top {
width: 542rpx;
margin-bottom: 12rpx;
}
.title_content {
display: flex;
flex-flow: row nowrap;
justify-content: left;
align-items: center;
color: #8C887C;
font-size: $uni-font-size-base;
.item {
margin-right: 10rpx;
}
}
}
}
.order_pay_info {
margin-top: 16rpx;
.pay_info_item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
margin-top: 26rpx;
.info_title {
color: $uni-text-color;
font-size: $uni-font-size-base;
}
.info_price {
color: $uni-text-color;
font-size: $uni-font-size-base;
}
.yellow_info {
color: #FFCD35
}
}
.couponList_item {
width: 654rpx;
height: 64rpx;
border-radius: 8rpx;
background: #F6F6F6;
padding: 10rpx 24rpx;
box-sizing: border-box;
}
}
}
.short_box {
// height: 272rpx;
padding-bottom: 0rpx;
background-color: #FFCD35;
.short_item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
margin-bottom: 26rpx;
.short_item_title {
color: $uni-text-color;
font-size: $uni-font-size-base;
font-weight: 500;
}
.short_item_time {
font-size: $uni-font-size-base;
color: #8C887C;
max-width: 500rpx;
text-align: right;
}
}
}
.short_box::after {
content: '';
display: table;
}
}
}
.isline {
text-decoration: line-through
}
</style>
+21
View File
@@ -0,0 +1,21 @@
<!-- 暂停 -->
<template>
<view class="content">
<web-view :src="webUrl"></web-view>
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
const webUrl = ref('')
onLoad((e) => {
webUrl.value = e.url
})
</script>
<style lang="scss">
.content {
width: 100%;
height: 100%;
}
</style>
+44
View File
@@ -0,0 +1,44 @@
// pinia 本地持久化插件
// import { getStorageSync, setStorageSync } from '';
const hydrateStore = (store, { key }) => {
try {
const value = uni.getStorageSync(key);
if (value) store.$patch(value);
} catch (error) {
console.error('--> piniaPersistedState.hydrateStore', error);
}
};
const persistState = (state, { key, paths }) => {
try {
if (!Array.isArray(paths)) return;
const toStore = paths.reduce((total, cur) => (state[cur] ? { ...total, [cur]: state[cur] } : total), {});
uni.setStorageSync(key, toStore);
} catch (error) {
console.error('--> piniaPersistedState.persistState', error);
}
};
export function createPersistedState() {
return context => {
const { options, store } = context;
const { id, persist } = options;
if (!persist) return;
const currentId = `store_${id}`;
const { paths } = persist;
hydrateStore(store, { key: currentId });
store.$subscribe(
(_mutation, state) => {
persistState(state, { key: currentId, paths });
},
{
detached: true,
}
);
};
}
+6
View File
@@ -0,0 +1,6 @@
export {};
declare module "vue" {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Some files were not shown because too many files have changed in this diff Show More