不甘寂寞 2年前
コミット
df1c7b505c

+ 771
- 679
after-sale/rescind-carId/rescind-carId-select.vue
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 153
- 0
after-sale/rescind-carId/verification.vue ファイルの表示

@@ -0,0 +1,153 @@
<template>
<view class="formBox">
<view class="from_item">
<text class="label">账号验证</text>
<input type="text" placeholder="输入验证码" v-model="model1.uname" placeholder-style="color:#000">
</view>
<view class="from_item">
<text class="label">手机号码</text>
<input type="text" placeholder="" v-model="model1.phone" placeholder-style="color:#000" disabled="true">
</view>
<view class="from_item">
<text class="label">验证码</text>
<input type="text" placeholder="请输入验证码" placeholder-style="color:#000">
<text class="btn" @click="getCode">获取验证码</text>
</view>
<button class="submit" @click="submit">验证</button>
</view>

</template>

<script setup lang="ts">
import {
reactive
} from "vue";
import {
navTo
} from "@/utils/utils"
import {
stringToJson
} from "../../utils/network/encryption.js";
import {
request
} from "../../utils/network/request.js";
import {
CardHangUpStatus
} from "@/utils/network/api.js"

let model1 = reactive({
uname: '输入验证码',
phone: '135****9090',
code: ''
})

const getCode = () => {
console.log(123);
}

const changeCardstatus = (type) => {
//参数说明
let options = {
type: 2, //type: 2,JSON格式提交数据(默认表单形式提交)
data: {
cardId: '', //卡号
obuId: "", //签号
reason: "", //原因
provider: '2', //挂起类型 2-有卡挂起,3-无卡挂起
operation: "1", //1-卡挂起, 2-牵挂起, 3-卡签挂起, 4-卡解挂 ,5-签解挂
orderId: '20230225155521777646302', //订单编号
}, //请求参数
method: "POST", //提交方式(默认POST)
showLoading: true, //是否显示加载中(默认显示)
};

//调用方式
request(CardHangUpStatus, options)
.then((res) => {
stringToJson(res.bizContent)
if (stringToJson(res.statusCode) == 0) {
navTo('/after-sale/card-release-pending/result')
}
})
.catch((err) => {
console.log(err);
});
}

const submit = () => {
console.log("111");
changeCardstatus()

}
</script>


<style>
page {
width: 100%;
height: 100%;
}
</style>

<style lang="scss" scoped>
.formBox {
height: 90%;
width: 100%;

// background-color: red;
.from_item {
padding: 30rpx;
padding-top: 60rpx;
position: relative;

.label {
font-size: 28rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #777777;
}

input {
font-size: 32rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #333333;
line-height: 58rpx;
border-bottom: 1rpx solid #DCDCDC;
margin-top: 50rpx;
padding-bottom: 10rpx;

}

.btn {
position: absolute;
right: 45rpx;
bottom: 48rpx;
background: transparent;
font-size: 30rpx;
color: #15E5C1;
z-index: 999;

}

}

.submit {
background: linear-gradient(to left, #43A1E0 0%, #13E7C1 100%);
width: 670rpx;
height: 80rpx;
line-height: 80rpx;
color: #fff;
border-radius: 100rpx;
position: fixed;
bottom: 100rpx;
left: 50%;
transform: translate(-50%);
font-size: 32rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
line-height: 80rpx;
}
}
</style>

+ 1
- 1
composables/order/useOrderSkip.ts ファイルの表示

@@ -108,7 +108,7 @@ export default function useOrderSkip(){
//去换货
const gotoExchangeOrder = (orderInfo:any) =>{
navTo(`/orders/apply-ex-goods?id=${orderInfo.id}`);
navTo(`/orders/apply-ex-goods-step1?orderId=${orderInfo.orderId}&id=${orderInfo.id}`);
}
//去激活订单

+ 1
- 1
manifest.json ファイルの表示

@@ -52,7 +52,7 @@
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "wx008c60533388527a",
"appid" : "wx214b4f8de36a0181",
"setting" : {
"urlCheck" : false,
"checkSiteMap" : false,

+ 301
- 0
orders/apply-ex-goods-step1.vue ファイルの表示

@@ -0,0 +1,301 @@
<template>
<!-- <navBar title="补办ETC卡"></navBar> -->
<view class="oderPage">
<u-form :model="form" ref="myForm" :error-type="errorType">
<view class="from">
<u-form-item prop="operation">
<view class="from_item">
<text><text style="color: red;">*</text>注销方式:</text>
<u-radio-group v-model="form.operation">
<u-radio :customStyle="{marginBottom: '8px'}" activeColor="#2CE242"
v-for="(item, index) in radiolist1" :key="index" :label="item.name" :name="item.name"
@change="radioChange">
{{item.disabled}}
</u-radio>
</u-radio-group>
</view>
</u-form-item>
<u-form-item prop="applyType">
<view class="from_item">
<text><text style="color: red;">*</text>申请类型:</text>
<view style="display: flex;" @click="showPicker">
<u-input v-model="applyType" class="input" disabled placeholder="请选择" />
<u-icon name="arrow-right" style="margin-left: 10px;display: flex;"></u-icon>
</view>
</view>
</u-form-item>
</view>
</u-form>
<button class="submit" @click="submit">下一步</button>
<!-- 自提网点弹窗 -->
<view>
<u-picker mode="selector" v-model="show" :range="columns" range-key="label" @confirm="confirm"></u-picker>
</view>
</view>

</template>

<script setup lang="ts">
import {
checkStr,
navTo
} from "@/utils/utils.ts"

import {
ref,
reactive
} from "vue";
import {
orderExchangeApply
} from "@/utils/network/api.js"
import {
request
} from "@/utils/network/request";
import {
stringToJson
} from "@/utils/network/encryption";
import {
getItem,
StorageKeys
} from "@/utils/storage";
import {
onReady
} from "@dcloudio/uni-app";
import {
onLoad
} from "@dcloudio/uni-app";

// 表单数据
const form = reactive({
orderId: '',
applyType: '',
operation: ''

})
//接受通过该id查询订单详情
const oldId=ref('')

const applyType = ref('')
//选择器数据
const columns = [{
label: '换货-换卡',
// 其他属性值
id: 'CARD '
},
{
label: '换货-换签',
// 其他属性值
id: 'OBU'
},
{
label: '换货-换卡签',
// 其他属性值
id: 'ALL'
},
{
label: '换卡签-换卡',
// 其他属性值
id: 'EXCHANGE_CARD'
},
{
label: '换卡签-换签',
// 其他属性值
id: 'EXCHANGE_OBU'
},
{
label: '换卡签-换卡签',
// 其他属性值
id: 'EXCHANGE_ALL'
},
]

// 验证规则
const rules = {
// applyType: [{
// required: true,
// message: '请选择申请类型',
// trigger: ['change', 'blur'],
// }],
// operation: [{
// required: true,
// message: '请选择注销方式',
// trigger: ['change', 'blur'],
// }]
}
// 验证提示类型(toast要版本为1.3.5才支持)
const errorType = ['message', 'border-bottom', 'toast']

// 设置验证规则
const myForm = ref(null)
onReady(() => {
myForm.value.setRules(rules)
})

// 单选数据列表
const radiolist1 = reactive([{
name: 1,
disabled: '有卡注销'
},
{
name: 2,
disabled: '无卡注销'
},
], )




let show = ref(false)

// 打开地区先择器
const showPicker = function() {
show.value = true
}
// 确定地区
const confirm = (e) => {
console.log(e);
form.applyType = columns[e].id
applyType.value = columns[e].label
}

// 单选
const radioChange = (n) => {
console.log('radioChange', n);
console.log(form);
}


// 提交
const submit = () => {

if (form.operation && form.applyType) {
console.log('验证通过', form);
navTo(`/orders/apply-ex-goods?orderId=${oldId.value}&id=8822ca31f88e448eb534767ba4d01eb9`) //测试用
// const options = {
// type: 2,
// data: form,
// method: "POST",
// showLoading: true,
// };
// request(orderExchangeApply, options).then((res) => {
// const data = stringToJson(res.bizContent);
// console.log(data);
// // navTo(`/orders/apply-ex-goods?orderId=${oldId.value}&id=${data.id}`)
// });
} else if (!form.applyType) {
uni.showToast({
title: "请选择申请类型",
icon: "none"
})
} else {
uni.showToast({
title: "请选择注销类",
icon: "none"
})
}




// myForm.value.validate((valid) => {
// console.log(valid);
// if (valid) {

// } else {
// console.log('验证未通过');
// }
// })
}


onLoad((option) => {
form.orderId = option.orderId
oldId.value=option.id
console.log(form);
});
</script>


<style>
page {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #F3F3F3;
}
</style>
<style lang="scss" scoped>
.oderPage {
flex: 1;
width: 100%;

.from {
background-color: #fff;
margin-top: 20rpx;

::v-deep .u-form-item {
padding: 0;
line-height: normal;

.u-form-item__message {
margin-bottom: 12rpx
}
}

.from_item {
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
padding: 0 30rpx;
// border-bottom: #DCDCDC 1px solid;
align-items: center;
height: 80rpx;

::v-deep .input {
text-align: right;
flex: 1;

input {
text-align: right;
}
}
}

.from_item1 {
display: flex;
flex-wrap: nowrap;
flex-direction: column;
justify-content: space-between;
padding: 30rpx;
border-bottom: #DCDCDC 1px solid;

input {
text-align: right;
}

.textarea {
background-color: #F1F1F1;
width: 100%;
border-radius: 20rpx;
margin-top: 10rpx;
text-indent: 1rem;
height: 180rpx;
padding: 20rpx;
box-sizing: border-box;
}
}
}
}

.submit {
background: linear-gradient(to left, #43A1E0 0%, #13E7C1 100%);
width: 670rpx;
height: 80rpx;
color: #fff;
border-radius: 100rpx;
margin: 26px auto;
font-size: 32rpx;
}
</style>

+ 4
- 2
orders/apply-ex-goods.vue ファイルの表示

@@ -64,7 +64,7 @@ const state = reactive({
divider: true,
},
{
title: "退货方式:",
title: "货方式:",
type: 7,
value: "exchangeMode",
star: true,
@@ -266,6 +266,7 @@ const getOrderDetails = (id) => {
};
request(orderDetail, options).then((res) => {
//回显订单信息
console.log(stringToJson(res.bizContent))
state.orderInfo = stringToJson(res.bizContent);
state.formData[0].hint = state.orderInfo.orderId;
state.formData[1].hint = state.orderInfo.vehiclePlate;
@@ -417,7 +418,8 @@ const submit = (e: any) => {
};

onLoad((option) => {
getOrderDetails(option.id);
console.log(option);//id是申请的接口获取的id
getOrderDetails(option.orderId);
getLogisticsList();
getOutletList();
});

+ 13
- 0
pages.json ファイルの表示

@@ -379,6 +379,13 @@
"enablePullDownRefresh": false
}
},
{
"path": "rescind-carId/verification",
"style": {
"navigationBarTitleText": "验证",
"enablePullDownRefresh": false
}
},
{
"path": "rescind-carId/base-change-people",
"style": {
@@ -819,6 +826,12 @@
"navigationBarTitleText": "申请换货"
}
},
{
"path": "apply-ex-goods-step1",
"style": {
"navigationBarTitleText": "申请换货"
}
},
{
"path": "apply-return-goods",
"style": {

+ 99
- 73
pages/order/components/order-list-item-new.vue ファイルの表示

@@ -7,12 +7,13 @@
<image :src="`${$imgUrl}order/icon-star-green.png`" class="icon"></image>
<text class="title">{{item.productName ?? ''}}</text>
</view>
<view class="status text-orange" v-if="item.orderStatus == OrderStatus.已取消">已取消</view>
<view class="status text-green" v-else
:class="{'text-orange':item.orderStep == OrderStatus.已完成 || item.orderStep == OrderStatus.已结束
:class="{'text-orange':item.orderStep == OrderStatus.已完成 || item.orderStep == OrderStatus.已结束
|| item.orderStep == OrderStatus['换货-设备已回收'] || item.orderStep == OrderStatus.退款成功 || item.orderStep == OrderStatus.退货成功}">
{{getOrderStatusName(item.orderStep)}}</view>
{{getOrderStatusName(item.orderStep)}}
</view>
</view>
<view class="detail">
<view class="orders">
@@ -33,45 +34,49 @@
<text class="value">{{getVehiclePlateColor(item.vehiclePlateColor)}}</text>
</view>
</view>
<view class="money"><text class="cny">¥</text><text class="amount">{{item.amount / 100 ?? '0.00'}}</text></view>
<view class="money"><text class="cny">¥</text><text class="amount">{{item.amount / 100 ?? '0.00'}}</text>
</view>
</view>
<template v-if="item.orderStatus != OrderStatus.已取消">
<!-- 信息填写未完成 -->
<view class="btns" v-if="item.orderStep == OrderStatus['完成个人/单位信息上传'] || item.orderStep == OrderStatus.完成填写基本信息 || item.orderStep == OrderStatus.完成车辆信息上传">
<view class="btns"
v-if="item.orderStep == OrderStatus['完成个人/单位信息上传'] || item.orderStep == OrderStatus.完成填写基本信息 || item.orderStep == OrderStatus.完成车辆信息上传">
<view class="btn btn-normal" @click.stop="gotoCancelOrder(item)">取消订单</view>
<view class="btn btn-primary" @click.stop="gotoEditUserOrUnitInfo(item)">继续申请</view>
</view>
<!-- 待支付 -->
<view class="btns" v-if="item.orderStep == OrderStatus.待支付">
<view class="btn btn-normal" @click.stop="gotoCancelOrder(item)">取消订单</view>
<view class="btn btn-primary" @click.stop="gotoOrderDetails(item)">支付</view>
</view>
<!-- 审核中/审核不通过 -->
<view class="btns" v-if="item.orderStep == OrderStatus.待审核 || item.orderStep == OrderStatus.审核不通过">
<view class="btn btn-normal" v-if="item.orderStep == OrderStatus.审核不通过" @click.stop="gotoEditUserOrUnitInfo(item)">修改资料</view>
<view class="btn btn-normal" v-if="item.orderStep == OrderStatus.审核不通过"
@click.stop="gotoEditUserOrUnitInfo(item)">修改资料</view>
<view class="btn btn-normal" @click.stop="gotoCancelOrder(item)">取消订单</view>
<view class="btn btn-primary" @click.stop="gotoOrderDetails(item)">修改地址</view>
</view>
<!-- 待发货 -->
<view class="btns" v-else-if="item.orderStep == OrderStatus.待发货">
<view class="btn btn-normal" @click.stop="gotoCancelOrder(item)">取消订单</view>
<view class="btn btn-primary" @click.stop="gotoOrderDetails(item)">修改地址</view>
</view>
<!-- 待收货 -->
<view class="btns" v-else-if="item.orderStep == OrderStatus.待收货">
<view class="btn btn-normal" @click.stop="gotoCheckLogistics(item)">查看物流
</view>
<view class="btn btn-normal" @click.stop="gotoReturnOrder(item)">申请退货
</view>
<view class="btn btn-normal" @click.stop="gotoExchangeOrder(item)">申请换货</view>
<view class="btn btn-primary" @click.stop="gotoConfirmReceipt(item)">确认收货
</view>
</view>
<!-- 待激活 -->
<view class="btns" v-else-if="item.orderStep == OrderStatus.待激活">
<view class="btn btn-normal" @click.stop="gotoReturnOrder(item)">申请退货</view>
@@ -79,18 +84,18 @@
<view class="btn btn-primary" @click.stop="gotoActiveOrder(item)">去激活
</view>
</view>
<!-- 已完成 -->
<view class="btns" v-else-if="item.orderStep == OrderStatus.已完成">
<view class="btn btn-primary" @click.stop="gotoEvaluateOrder(item)" v-if="!item.appraise">去评价</view>
<view class="btn btn-normal" v-else>已评价</view>
</view>
<!-- 已结束 -->
<view class="btns" v-else-if="item.orderStep == OrderStatus.已结束">
<view class="btn btn-primary" @click.stop="showActiveOrder = true">重新激活订单</view>
</view>
<!-- 换货中 -->
<view class="btns" v-else-if="item.orderStep == OrderStatus['已申请-换货']">
<!-- 查看物流: 原型没有UI有 -->
@@ -99,43 +104,64 @@
</view>
</template>
</view>
<!-- 弹窗 -->
<u-popup v-model="showActiveOrder" mode="center" >
<popup-active-order content="确认是否重新激活订单" @cancel="showActiveOrder = false" @confirm="toActiveOrder"></popup-active-order>
<u-popup v-model="showActiveOrder" mode="center">
<popup-active-order content="确认是否重新激活订单" @cancel="showActiveOrder = false" @confirm="toActiveOrder">
</popup-active-order>
</u-popup>
</template>

<script lang="ts" setup>
import popupActiveOrder from "./popup-active-order.vue";
import useOrderSkip from "@/composables/order/useOrderSkip";
import {getOrderStatusName,msg,getOrderTypeName} from "@/utils/utils";
import { ref } from "vue";
import {OrderStatus} from "@/datas/enum";
import {vehiclePlateColor} from "@/datas/vehiclePlateColor";
import {
getOrderStatusName,
msg,
getOrderTypeName
} from "@/utils/utils";
import {
ref
} from "vue";
import {
OrderStatus
} from "@/datas/enum";
import {
vehiclePlateColor
} from "@/datas/vehiclePlateColor";

defineProps({
item: {
type: Object,
default: () => ({}),
},
item: {
type: Object,
default: () => ({}),
},
});
//是否确认激活订单弹窗
const showActiveOrder = ref(false);
//办理订单按钮跳转业务逻辑
const {gotoEditAddress,gotoCancelOrder,gotoEditUserOrUnitInfo,
gotoConfirmReceipt,gotoCheckLogistics,gotoEvaluateOrder,
gotoActiveOrder,gotoReturnOrder,gotoExchangeOrder,gotoPay,gotoOrderDetails} = useOrderSkip();
const {
gotoEditAddress,
gotoCancelOrder,
gotoEditUserOrUnitInfo,
gotoConfirmReceipt,
gotoCheckLogistics,
gotoEvaluateOrder,
gotoActiveOrder,
gotoReturnOrder,
gotoExchangeOrder,
gotoPay,
gotoOrderDetails
} = useOrderSkip();

//激活订单
const toActiveOrder = (item) =>{
const toActiveOrder = (item) => {
gotoActiveOrder(item);
showActiveOrder.value = false;
showActiveOrder.value = false;
}
//获取车牌颜色文字
const getVehiclePlateColor = (id:number)=>{
const getVehiclePlateColor = (id: number) => {

const colors = vehiclePlateColor.filter(item => item.id == id);
return colors[0].color
@@ -152,11 +178,11 @@
flex-direction: column;
margin: 30rpx 30rpx 0rpx;
}
.bg-white .item {
box-shadow: 0rpx 4rpx 13rpx 3rpx rgba(223, 223, 223, 0.8);
}
.item .head {
display: flex;
justify-content: space-between;
@@ -164,7 +190,7 @@
padding: 20rpx 28rpx;
border-bottom: 1px solid #dcdcdc;
}
.item .head {
.head-row {
display: flex;
@@ -172,9 +198,9 @@
justify-content: space-between;
align-items: center;
}
.name {}
.name>text {
font-size: 26rpx;
font-family: Noto Sans S Chinese;
@@ -183,38 +209,38 @@
line-height: 36rpx;
}
}
.item .head .icon {
width: 48rpx;
height: 48rpx;
}
.item .head .name {
display: flex;
align-items: center;
}
.text-green {
font-size: 26rpx;
color: #00b38b;
}
.text-orange {
font-size: 26rpx;
color: #ff8000;
}
.text-black {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.title {
font-size: 30rpx;
color: #333;
}
.tag-green {
font-size: 22rpx;
height: 40rpx;
@@ -224,7 +250,7 @@
background: #d9f4ee;
color: #00b38b;
}
.tag-grey {
font-size: 22rpx;
height: 40rpx;
@@ -234,54 +260,54 @@
background: #e8e8e8;
color: #666;
}
.detail {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 32rpx;
}
.detail .type {
font-size: 26rpx;
color: #999;
}
.detail .value {
font-size: 26rpx;
color: #333;
}
.finished .detail .value {
color: #999;
}
.detail .odd {
margin: 20rpx 0;
}
.cny {
font-size: 26rpx;
color: #333;
}
.finished .cny {
color: #999;
}
.amount {
font-size: 40rpx;
font-weight: bold;
}
.bottom .amount {
color: #ff8000;
}
.finished .amount {
color: #999;
}
.btns {
position: relative;
display: flex;
@@ -291,7 +317,7 @@
margin: 0 30rpx;
padding: 20rpx 0;
}
.bottom {
display: flex;
justify-content: space-between;
@@ -300,23 +326,23 @@
margin: 0 30rpx;
padding: 20rpx 0;
}
.btn {
.btn {
height: 60rpx;
line-height: 58rpx;
border-radius: 30rpx;
padding: 0 24rpx;
font-size: 26rpx;
font-size: 20rpx;
box-sizing: border-box;
margin-right: 20rpx;
}
.btns .btn:last-child {
margin: 0;
}
.btns .state {
position: absolute;
left: 0;
@@ -325,7 +351,7 @@
font-weight: 400;
color: #999999;
line-height: 58rpx;
text {
font-size: 26rpx;
font-family: Noto Sans S Chinese;
@@ -334,20 +360,20 @@
line-height: 58rpx;
}
}
.btn-primary {
border: 1px solid #00b38b;
color: #00b38b;
}
.btn-disable {
border: 1px solid #999;
color: #999;
}
.btn-normal {
border: 1px solid #dcdcdc;
color: #333;
}
</style>
</style>

+ 465
- 467
personal-center/setting/car-information/car-change.vue ファイルの表示

@@ -1,475 +1,473 @@
<template>
<view class="content">
<view class="item-tips">
<view class="title"> 上传后请核对识别信息 </view>
<view class="tip"> 如有错误请及时手动修改 </view>
</view>
<view class="picture-wrapper" @click="cardImageOcr('1')">
<view class="bg">
<view class="">
<view class="name"> 行驶证主页 </view>
<view class="value"> 上传行驶证的主页 </view>
<view class="tip">
<view class="tip-value"> 拍摄规范 </view>
</view>
</view>

<image
v-if="!state.form.vehPosImgUrl"
class="icon"
:src="`${$imgUrl}applyCard/car-zhu.png`"
>
</image>
<image v-else class="icon" :src="state.form.vehPosImgUrl"></image>
</view>
</view>
<view class="picture-wrapper" @click="cardImageOcr('2')">
<view class="bg">
<view class="">
<view class="name"> 行驶证副页 </view>
<view class="value"> 上传行驶证的副页 </view>
<view class="tip">
<view class="tip-value"> 拍摄规范 </view>
</view>
</view>
<image
v-if="!state.form.vehNegImgUrl"
class="icon"
:src="`${$imgUrl}applyCard/car-fu.png`"
>
</image>
<image v-else class="icon" :src="state.form.vehNegImgUrl"></image>
</view>
</view>
<view class="picture-wrapper" @click="cardFileImageUpdate()">
<view class="bg">
<view class="">
<view class="name"> 车头照 </view>
<view class="value"> 上传汽车的车头照片 </view>
<view class="tip">
<view class="tip-value"> 拍摄规范 </view>
</view>
</view>
<image
v-if="!state.form.vehBodyUrl"
class="icon"
:src="`${$imgUrl}applyCard/chetou.png`"
>
</image>
<image v-else class="icon" :src="state.form.vehBodyUrl"></image>
</view>
</view>
<view class="shibie-wrapper">
<view class="title"> 识别内容如下 </view>
<view class="">
<u-form label-width="200" :model="state.form" ref="uForm">
<u-form-item label="车牌号">
<u-input inputAlign="right" v-model="state.form.vehicleId" />
</u-form-item>

<u-form-item label="所有人">
<u-input inputAlign="right" v-model="state.form.man" />
</u-form-item>
<u-form-item label="车辆类型">
<u-input inputAlign="right" v-model="state.form.vehicleType" />
</u-form-item>
<u-form-item label="使用性质">
<u-input inputAlign="right" v-model="state.form.character" />
</u-form-item>
<u-form-item label="车辆识别代号">
<u-input inputAlign="right" v-model="state.form.vin" />
</u-form-item>
<u-form-item label="发动机号码">
<u-input inputAlign="right" v-model="state.form.engineNum" />
</u-form-item>

<u-form-item label="注册日期">
<u-input inputAlign="right" v-model="state.form.register" />
</u-form-item>
<u-form-item label="发证日期">
<u-input inputAlign="right" v-model="state.form.issueDate" />
</u-form-item>
<u-form-item label="核定载人数">
<u-input inputAlign="right" v-model="state.form.approvedCount" />
</u-form-item>
<u-form-item label="整备质量">
<u-input inputAlign="right" v-model="state.form.maintenaceMass" />
</u-form-item>
<u-form-item label="外廊尺寸">
<u-input
inputAlign="right"
v-model="state.form.vehicleDimensions"
/>
</u-form-item>
<u-form-item label="总质量">
<u-input inputAlign="right" v-model="state.form.totalMass" />
</u-form-item>
<u-form-item label="车辆用户类型">
<u-input
@click="state.actionSheetShow = true"
inputAlign="right"
v-model="state.form.useUserTypeName"
type="select"
/>
</u-form-item>
</u-form>
</view>
</view>
<view class="green-tip">
如识别信息有误,请手动修改,确认无误后,点击下一步!
</view>

<view class="action">
<button type="default" class="button" @click="savaHandle()">
下一步
</button>
</view>
<u-select
v-model="state.actionSheetShow"
:list="state.actionSheetList"
@confirm="selectConfirm"
></u-select>
</view>
<view class="content">
<view class="item-tips">
<view class="title"> 上传后请核对识别信息 </view>
<view class="tip"> 如有错误请及时手动修改 </view>
</view>
<view class="picture-wrapper" @click="cardImageOcr('1')">
<view class="bg">
<view class="">
<view class="name"> 行驶证主页 </view>
<view class="value"> 上传行驶证的主页 </view>
<view class="tip">
<view class="tip-value"> 拍摄规范 </view>
</view>
</view>

<image v-if="!state.form.drivingPermitPos" class="icon" :src="`${$imgUrl}applyCard/car-zhu.png`">
</image>
<image v-else class="icon" :src="state.form.drivingPermitPos"></image>
</view>
</view>
<view class="picture-wrapper" @click="cardImageOcr('2')">
<view class="bg">
<view class="">
<view class="name"> 行驶证副页 </view>
<view class="value"> 上传行驶证的副页 </view>
<view class="tip">
<view class="tip-value"> 拍摄规范 </view>
</view>
</view>
<image v-if="!state.form.drivingPermitNeg" class="icon" :src="`${$imgUrl}applyCard/car-fu.png`">
</image>
<image v-else class="icon" :src="state.form.drivingPermitNeg"></image>
</view>
</view>
<view class="picture-wrapper" @click="cardFileImageUpdate()">
<view class="bg">
<view class="">
<view class="name"> 车头照 </view>
<view class="value"> 上传汽车的车头照片 </view>
<view class="tip">
<view class="tip-value"> 拍摄规范 </view>
</view>
</view>
<image v-if="!state.form.vehBodyUrl" class="icon" :src="`${$imgUrl}applyCard/chetou.png`">
</image>
<image v-else class="icon" :src="state.form.vehBodyUrl"></image>
</view>
</view>
<view class="shibie-wrapper">
<view class="title"> 识别内容如下 </view>
<view class="">
<u-form label-width="200" :model="state.form" ref="uForm">
<u-form-item label="车牌号">
<u-input inputAlign="right" v-model="state.form.vehicleId" />
</u-form-item>

<u-form-item label="所有人">
<u-input inputAlign="right" v-model="state.form.man" />
</u-form-item>
<u-form-item label="车辆类型">
<u-input inputAlign="right" v-model="state.form.vehicleType" />
</u-form-item>
<u-form-item label="使用性质">
<u-input inputAlign="right" v-model="state.form.character" />
</u-form-item>
<u-form-item label="车辆识别代号">
<u-input inputAlign="right" v-model="state.form.vin" />
</u-form-item>
<u-form-item label="发动机号码">
<u-input inputAlign="right" v-model="state.form.engineNum" />
</u-form-item>

<u-form-item label="注册日期">
<u-input inputAlign="right" v-model="state.form.register" />
</u-form-item>
<u-form-item label="发证日期">
<u-input inputAlign="right" v-model="state.form.issueDate" />
</u-form-item>
<u-form-item label="核定载人数">
<u-input inputAlign="right" v-model="state.form.approvedCount" />
</u-form-item>
<u-form-item label="整备质量">
<u-input inputAlign="right" v-model="state.form.maintenaceMass" />
</u-form-item>
<u-form-item label="外廊尺寸">
<u-input inputAlign="right" v-model="state.form.vehicleDimensions" />
</u-form-item>
<u-form-item label="总质量">
<u-input inputAlign="right" v-model="state.form.totalMass" />
</u-form-item>
<u-form-item label="车辆用户类型">
<u-input @click="state.actionSheetShow = true" inputAlign="right"
v-model="state.form.useUserTypeName" type="select" />
</u-form-item>
</u-form>
</view>
</view>
<view class="green-tip">
如识别信息有误,请手动修改,确认无误后,点击下一步!
</view>

<view class="action">
<button type="default" class="button" @click="savaHandle()">
下一步
</button>
</view>
<u-select v-model="state.actionSheetShow" :list="state.actionSheetList" @confirm="selectConfirm"></u-select>
</view>
</template>

<script setup lang="ts">
import { reactive } from "vue";
import navBgCar from "./components/nav-bg-car3";
import navBar from "../../components/nav-bar/nav-bar2.vue";
import { pathToBase64 } from "@/utils/util/imageTool.js";
import {
etcCarCardInfoSubmit,
etcCarOcrCard,
fileUpload,
} from "@/utils/network/api.js";
import { request } from "@/utils/network/request.js";

import { stringToJson } from "@/utils/network/encryption";
import { onLoad, onShow } from "@dcloudio/uni-app";

const savaHandle = () => {
var data = state.form;
const options = {
type: 2,
data: data,
method: "POST",
showLoading: true,
};
request(etcCarCardInfoSubmit, options).then((res) => {
const data = stringToJson(res.bizContent);
uni.navigateTo({
url: `/pages/applyCard/release-products?orderId=${state.orderId}`,
});
});
};

const selectConfirm = (item: any) => {
item.map((val, index) => {
state.form.useUserType = val.value;
state.form.useUserTypeName = val.label;
});
};

const cardFileImageUpdate = () => {
uni.chooseImage({
count: 1, //只能选取一张照片
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["camera", "album"], //从相册选择
success: function (res) {
pathToBase64(res.tempFilePaths[0])
.then((path) => {
var data = {
fileBase64: path,
};

const options = {
type: 2,
data: data,
method: "POST",
showLoading: true,
};
request(fileUpload, options).then((res) => {
const data = stringToJson(res.bizContent);
console.log(data);
state.form.vehBodyUrl = data.data.url;
});
})
.catch((error) => {});
},
});
};

const state = reactive({
actionSheetShow: false,
actionSheetList: [
{
label: "普通车",
value: 0,
},
{
label:
"道路运输证经营范围仅有“货物专用运输(集装箱) ”的牵引车办理J类型集装箱",
value: 24,
},
{
label: "道路运输证经营范围不含“货物专用运输(集装箱)”的牵引车",
value: 27,
},
{
label:
'道路运输证经营范围除“货物专用运输 (集装 箱)"外,还有“普通货运”等其他项目的牵引车办理J2类型集装箱',
value: 28,
},
],
form: {
orderId: "", //订单ID
man: "", //所有人
character: "", //使用性质
register: "", //注册日期

customerId: "", //用户编号
vehicleId: "", //车牌编号
issueDate: "", //发证日期
vehPosImgUrl: "", //行驶证正面
vehNegImgUrl: "", //行驶证证反面
type: "0", //0,客车 1.货车
useUserType: 0, //车辆用户类型
useUserTypeName: "普通车",
vehicleSign: 2, //前/后装标识
vin: "", //车辆识别代号
engineNum: "", //发动机号码
vehicleType: "", //车辆类型
vehicleModel: "", //行驶证品牌型号
approvedCount: undefined, //核定人数
totalMass: undefined, //总质量
maintenaceMass: undefined, //整备质量
permittedWeight: "", //核定载质量
vehicleDimensions: "", //车辆尺寸
permittedTowWeight: "", //准牵引总质量
axleCount: "", //车轴数
ownerName: "", //车主姓名
ownerIdType: "", //车主证件类型
ownerIdNum: "", //车主证件号码
ownPosImgUrl: "", //车主证件正面图片
ownNegImgUrl: "", //车主证件反面图片
agreementId: "", //签约编号
channelId: "5201018892300000001", //编号渠道
scenePayType: "", //
transportIdNum: "", //道路运输证编号
licenseIdNum: "", //经营许可证编号
vehBodyUrl: "", //车身照片
proxyUrl: "", //委托书地址
},
orderId: "",
isMyPeopple: true,
});
onLoad((option: any) => {
state.form.orderId = option.orderId;
});
//orc接口调用
const cardImageOcr = (val: any) => {
var imageType = val;
uni.chooseImage({
count: 1, //只能选取一张照片
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["camera", "album"], //从相册选择
success: function (res) {
pathToBase64(res.tempFilePaths[0])
.then((path) => {
var data = {
source: "1",
agencyId: "52010106004",
imageType: imageType,
fileName: res.tempFilePaths[0],
imageBase64: path,
};

const options = {
type: 2,
data: data,
method: "POST",
showLoading: true,
};
request(etcCarOcrCard, options).then((res) => {
const data = stringToJson(res.bizContent);
console.log(data);
if (val === "1") {
state.form.vehicleId = data.plate_a;
state.form.man = data.man;
state.form.vehicleType = data.vehicle;
state.form.character = data.character;
state.form.vin = data.vin;
state.form.engineNum = data.engine;
state.form.register = data.register;
state.form.issueDate = data.issue;
state.form.vehPosImgUrl = data.imageUrl;
state.form.vehicleModel = data.model;
} else {
state.form.approvedCount = parseFloat(data.apc);
state.form.maintenaceMass = parseFloat(data.unladen);
state.form.vehicleDimensions = data.overall;
state.form.totalMass = parseFloat(data.gross);
state.form.vehNegImgUrl = data.imageUrl;
}
});
})
.catch((error) => {});
},
});
};
import {
reactive
} from "vue";
import navBgCar from "./components/nav-bg-car3";
import navBar from "../../components/nav-bar/nav-bar2.vue";
import {
pathToBase64
} from "@/utils/util/imageTool.js";
import {
etcCarCardInfoSubmit,
etcCarOcrCard,
fileUpload,
changecarInfo,
} from "@/utils/network/api.js";
import {
request
} from "@/utils/network/request.js";

import {
stringToJson
} from "@/utils/network/encryption";
import {
onLoad,
onShow
} from "@dcloudio/uni-app";

const savaHandle = () => {
var data = state.form;
console.log(data, "##########");
const options = {
type: 2,
data: data,
method: "POST",
showLoading: true,
};
request(changecarInfo, options).then((res) => {
const data = stringToJson(res.bizContent);
console.log(data)
uni.navigateTo({
// url: `/pages/applyCard/release-products?orderId=${state.orderId}`,
});
});
};

const selectConfirm = (item: any) => {
item.map((val, index) => {
state.form.useUserType = val.value;
state.form.useUserTypeName = val.label;
});
};

const cardFileImageUpdate = () => {
uni.chooseImage({
count: 1, //只能选取一张照片
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["camera", "album"], //从相册选择
success: function(res) {
pathToBase64(res.tempFilePaths[0])
.then((path) => {
var data = {
fileBase64: path,
};

const options = {
type: 2,
data: data,
method: "POST",
showLoading: true,
};
request(fileUpload, options).then((res) => {
const data = stringToJson(res.bizContent);
console.log(data);
state.form.vehBodyUrl = data.data.url;
});
})
.catch((error) => {});
},
});
};

const state = reactive({
actionSheetShow: false,
actionSheetList: [{
label: "普通车",
value: 0,
},
{
label: "道路运输证经营范围仅有“货物专用运输(集装箱) ”的牵引车办理J类型集装箱",
value: 24,
},
{
label: "道路运输证经营范围不含“货物专用运输(集装箱)”的牵引车",
value: 27,
},
{
label: '道路运输证经营范围除“货物专用运输 (集装 箱)"外,还有“普通货运”等其他项目的牵引车办理J2类型集装箱',
value: 28,
},
],
form: {
openId: 'ef0bf3bc54df4b09ae6ee3ff1cbc6f9d', //用户标识.
orderId: "", //订单ID
man: "", //所有人
character: "", //使用性质
register: "", //注册日期
customerId: "", //用户编号 .
vehicleId: "", //车牌编号 .
issueDate: "", //发证日期 .
drivingPermitPos: "", //行驶证正面 .
drivingPermitNeg: "", //行驶证证反面 .
type: "0", //0,客车 1.货车 .
useUserType: 0, //车辆用户类型 .
// useUserTypeName: "普通车",
vehicleSign: 2, //前/后装标识 .
vin: "", //车辆识别代号 .
engineNum: "", //发动机号码 .
vehicleType: "", //车辆类型 .
vehicleModel: "", //行驶证品牌型号 .
approvedCount: undefined, //核定人数 .
totalMass: undefined, //总质量 .
maintenaceMass: undefined, //整备质量.
permittedWeight: "", //核定载质量 .
vehicleDimensions: "", //车辆尺寸 .
permittedTowWeight: "", //准牵引总质量 .
axleCount: "", //车轴数 .
ownerName: "", //车主姓名
ownerIdType: "", //车主证件类型
ownerIdNum: "", //车主证件号码
ownPosImgUrl: "", //车主证件正面图片
ownNegImgUrl: "", //车主证件反面图片
agreementId: "", //签约编号
channelId: "", //编号渠道
scenePayType: "", //
transportIdNum: "", //道路运输证编号
licenseIdNum: "", //经营许可证编号
vehBodyUrl: "", //车身照片
proxyUrl: "", //委托书地址,
emergencyFlag: '', //应急车辆标识 0-非应急车辆 1-应急车辆
contacts: '', //指定联系人列表
ownerAddress: '', //所有人联系地址
axisType: '', //轴型
ownerTel: '', //所有人联系方式
axleDistance: '', //轴距
testRecord: '', //检验记录
fileNum: '', //档案编号
useCharacter: '', //车辆使用性质
registerDate: '' //注册日期
},
orderId: "",
isMyPeopple: true,
});
onLoad((option: any) => {
state.form.orderId = option.orderId;
});
//orc接口调用
const cardImageOcr = (val: any) => {
var imageType = val;
uni.chooseImage({
count: 1, //只能选取一张照片
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["camera", "album"], //从相册选择
success: function(res) {
pathToBase64(res.tempFilePaths[0])
.then((path) => {
var data = {
source: "1",
agencyId: "52010106004",
imageType: imageType,
fileName: res.tempFilePaths[0],
imageBase64: path,
};

const options = {
type: 2,
data: data,
method: "POST",
showLoading: true,
};
request(etcCarOcrCard, options).then((res) => {
const data = stringToJson(res.bizContent);
console.log(data);
if (val === "1") {
state.form.vehicleId = data.plate_a;
state.form.man = data.man;
state.form.vehicleType = data.vehicle;
state.form.character = data.character;
state.form.vin = data.vin;
state.form.engineNum = data.engine;
state.form.register = data.register;
state.form.issueDate = data.issue;
state.form.drivingPermitPos = data.imageUrl;
state.form.vehicleModel = data.model;
} else {
state.form.approvedCount = parseFloat(data.apc);
state.form.maintenaceMass = parseFloat(data.unladen);
state.form.vehicleDimensions = data.overall;
state.form.totalMass = parseFloat(data.gross);
state.form.drivingPermitNeg = data.imageUrl;
}
});
})
.catch((error) => {});
},
});
};
</script>

<style lang="scss" scoped>
.content {
position: relative;
// margin-top: -50rpx;
padding: 0rpx 30rpx;
position: relative;

.img-pos {
position: absolute;
left: 270rpx;
top: -38rpx;
right: 50rpx;

.img-flex {
display: flex;
justify-content: space-between;
align-items: center;

.car-img {
width: 86rpx;
height: 42rpx;
}
.flag-img {
width: 30rpx;
height: 35rpx;
}
}
}
.action {
padding-left: 20rpx;
padding-right: 20rpx;
padding-bottom: 30rpx;
.button {
height: 80rpx;
background: linear-gradient(-90deg, #43a1e0 0%, #13e7c1 100%);
border-radius: 40rpx;
font-size: 32rpx;
font-weight: 400;
color: #ffffff;
line-height: 80rpx;
}
}
.item-tips {
.title {
font-size: 30rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #000000;
line-height: 24rpx;
}
.tip {
margin-top: 16rpx;
font-size: 24rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #999999;
line-height: 24rpx;
}
}
.picture-wrapper {
margin-top: 40rpx;
.bg {
background: #ffffff;
box-shadow: 0rpx 4rpx 13rpx 3rpx rgba(223, 223, 223, 0.8);
border-radius: 20rpx;
padding: 40rpx;
display: flex;
// align-items: center;
justify-content: space-between;
.name {
font-size: 34rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #000000;
line-height: 34rpx;
}
.value {
margin-top: 20rpx;
font-size: 24rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #999999;
line-height: 24rpx;
}
.tip {
margin-top: 20rpx;
text-align: center;
width: 110rpx;
height: 40rpx;
background: rgba(33, 190, 177, 0.2);
border-radius: 6rpx;
.tip-value {
font-size: 20rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #0a8f8a;
line-height: 40rpx;
opacity: 1;
}
}
}
.icon {
width: 294rpx;
height: 188rpx;
}
}
.shibie-wrapper {
margin-top: 60rpx;
.title {
font-size: 30rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #000000;
line-height: 30rpx;
}
}
.buchong-wrapper {
margin-top: 60rpx;
.title {
font-size: 30rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #000000;
line-height: 30rpx;
}
}
.green-tip {
margin-top: 50rpx;
font-size: 24rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #00b38b;
line-height: 24rpx;
margin-bottom: 60rpx;
}
}
.content {
position: relative;
// margin-top: -50rpx;
padding: 0rpx 30rpx;
position: relative;
.img-pos {
position: absolute;
left: 270rpx;
top: -38rpx;
right: 50rpx;
.img-flex {
display: flex;
justify-content: space-between;
align-items: center;
.car-img {
width: 86rpx;
height: 42rpx;
}
.flag-img {
width: 30rpx;
height: 35rpx;
}
}
}
.action {
padding-left: 20rpx;
padding-right: 20rpx;
padding-bottom: 30rpx;
.button {
height: 80rpx;
background: linear-gradient(-90deg, #43a1e0 0%, #13e7c1 100%);
border-radius: 40rpx;
font-size: 32rpx;
font-weight: 400;
color: #ffffff;
line-height: 80rpx;
}
}
.item-tips {
.title {
font-size: 30rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #000000;
line-height: 24rpx;
}
.tip {
margin-top: 16rpx;
font-size: 24rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #999999;
line-height: 24rpx;
}
}
.picture-wrapper {
margin-top: 40rpx;
.bg {
background: #ffffff;
box-shadow: 0rpx 4rpx 13rpx 3rpx rgba(223, 223, 223, 0.8);
border-radius: 20rpx;
padding: 40rpx;
display: flex;
// align-items: center;
justify-content: space-between;
.name {
font-size: 34rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #000000;
line-height: 34rpx;
}
.value {
margin-top: 20rpx;
font-size: 24rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #999999;
line-height: 24rpx;
}
.tip {
margin-top: 20rpx;
text-align: center;
width: 110rpx;
height: 40rpx;
background: rgba(33, 190, 177, 0.2);
border-radius: 6rpx;
.tip-value {
font-size: 20rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #0a8f8a;
line-height: 40rpx;
opacity: 1;
}
}
}
.icon {
width: 294rpx;
height: 188rpx;
}
}
.shibie-wrapper {
margin-top: 60rpx;
.title {
font-size: 30rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #000000;
line-height: 30rpx;
}
}
.buchong-wrapper {
margin-top: 60rpx;
.title {
font-size: 30rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #000000;
line-height: 30rpx;
}
}
.green-tip {
margin-top: 50rpx;
font-size: 24rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #00b38b;
line-height: 24rpx;
margin-bottom: 60rpx;
}
}
</style>

+ 9
- 0
utils/network/api.js ファイルの表示

@@ -30,6 +30,9 @@ export const etcUserCardInfoSubmit = "22"; // CSMSN-提交个人用户信息
export const etcUserCardInfoChange = "21"; // CSMSN-更改个人用户信息
export const etcCarCardInfoSubmit = "18"; // CSMSN-提交车辆信息
export const etcQyList = "66"; // 统一会员平台可签约渠道列表查询接口
export const exchangeApply='888' //8.99.ASS-换货/换卡签申请接口
export const exchangeFillIn='887' //8.100. ASS-换货/换卡签填写信息接口
export const exchangeProcess='886' //8.101.ASS-换货/换卡签审核接口
/*******************蓝牙 start*************/
/* 开卡 * 50->51->52->73->51*/
@@ -76,13 +79,17 @@ export const getLogistics = "30"; //获取所有的快递公司信息
export const editOrderAddr = '164'; //订单修改收货地址
export const orderReturn = '165'; //订单申请退货
export const orderExchange = '167'; //订单申请换货
export const orderExchangeApply = '888'; //8.100.ASS-换货/换卡签申请接口
export const outletList = '168'; //根据机构号获取服务网点信息
export const orderEvaluate = '169'; //评价订单
export const orderEvaluateTag = '170'; //获取服务评价标签
//个人中心
export const changePassword = "94"; //重置密码
export const changePhone = "220"; //修改手机号
export const changecarInfo = "1029"; //车辆管理信息修改
// 售后管理
export const CardSignCancellation = "146"; //卡签注销
@@ -92,6 +99,8 @@ export const labelHangUp = "87"; //签挂起
export const CardRelease = "86"; //卡解挂
export const CardHangUpStatus = "81"; //卡挂起
export const CardlossStatus = '82' //卡签挂失/解挂
export const relieveCarId= '932' //车辆释放信息增加接口(解除车牌占用)
//圈层
export const quanCheck = "69"; //圈层检测

+ 2
- 2
utils/network/request.js ファイルの表示

@@ -35,8 +35,8 @@ export function request(code, options = {}) {
}
//Url 地址
//options.url = envs[process.env.NODE_ENV].baseUrl || '' + options.url
// options.url = 'http://192.168.100.63:8087/ifzt/api/interfaceMidGroundIn'
options.url = 'http://222.85.144.89:19002/ifzt/api/interfaceMidGroundIn'
options.url = 'http://192.168.100.63:8087/ifzt/api/interfaceMidGroundIn'
// options.url = 'http://222.85.144.89:19002/ifzt/api/interfaceMidGroundIn'
//判断baseUri是否为空
if (options.baseUrl) {
options.url = options.baseUrl

+ 4
- 4
utils/util/fileData.js ファイルの表示

@@ -1,7 +1,7 @@
import {
TextEncoder,
TextDecoder
} from "text-decoding";
// import {
// TextEncoder,
// TextDecoder
// } from "text-decoding";


export function IntegerToHexString(num, nLen) {

読み込み中…
キャンセル
保存