Browse Source

联调 种植计划

master
邓宏 2 years ago
parent
commit
77b8a5e471
  1. 5
      common/request.js
  2. 45
      components/form.vue
  3. 9
      pages/home/index.vue
  4. 48
      pages/massif/detail.vue
  5. 20
      pages/massif/index.vue
  6. 12
      pages/massif/info.vue
  7. 8
      pages/massif/mana/index.vue
  8. 52
      pages/massif/mana/plantPlan.vue
  9. 66
      pages/massif/plant_plan.vue
  10. 37
      pages/purchase/agrProdList.vue
  11. 21
      pages/purchase/apply.vue
  12. 11
      pages/purchase/specs.vue
  13. 0
      uni_modules/d-search/changelog.md
  14. 45
      uni_modules/d-search/components/d-search/d-search.vue
  15. 81
      uni_modules/d-search/package.json
  16. 1
      uni_modules/d-search/readme.md
  17. 8
      uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue

5
common/request.js

@ -3,7 +3,8 @@ import store from "@/store"
export function host(host='default',suffix='/plant_manage'){
return(
process.env.NODE_ENV === 'development'?{
default:`http://jtsfcq.natappfree.cc${suffix}`
// default:`http://f27zx4.natappfree.cc${suffix}` //陈
default:`http://jtsfcq.natappfree.cc${suffix}` //马
}:{
default:`http://qv6mj8.natappfree.cc${suffix}`
}
@ -59,7 +60,7 @@ const request=async function(url,param={}){
if(res){
if(res.data.code==401){
uni.reLaunch({
url:"pages/home/login",
url:"/pages/home/login",
})
return{statu:false, msg:"登录超时!"}
}

45
components/form.vue

@ -104,7 +104,7 @@
}
}
}
.checkBox{
.checkBox,.radio{
margin-top:14rpx;
}
.calendar{
@ -158,6 +158,11 @@
-
<text style="margin-left:20rpx;" :class="{noData:!value[1]}" @click="dateType='end';show=true">{{value[1]||endPlaceholder||'结束时间'}}</text>
</view>
<view v-if="type=='radio'" class="radio">
<u-radio-group :value="value" shape="square" @change="$emit('input',$event)" activeColor="#D9F6E9" iconColor="#10C176">
<u-radio :customStyle="{marginRight: '30rpx'}" v-for="(v, k) in columns" :key="k" :label="v.label" :name="v.value"/>
</u-radio-group>
</view>
<view v-if="type=='checkBox'" class="checkBox">
<u-checkbox-group :value="[]" @change="$emit('select',$event)" >
<u-checkbox :customStyle="{marginRight: '30rpx'}" v-for="(v, k) in columns" :key="k" activeColor="#D9F6E9" iconColor="#10C176" :label="v.label" :name="v.value" />
@ -172,11 +177,13 @@
:columns="columns"
:show="show"
keyName="label"
:defaultIndex="[value||0]"
ref="picker"
:defaultIndex="(value||[]).map(v=>v||0)"
closeOnClickOverlay
@close="show=false"
@cancel="show=false"
@confirm="$emit('select',$event.indexs[0]);show=false"/>
@confirm="$emit('select',$event.indexs[0]);show=false"
@change="pickerChange"/>
<u-datetime-picker
v-if="type=='dateRange'"
:show="show"
@ -194,12 +201,21 @@
:insert="false"
lunar
@confirm="$emit('input',$event.fulldate)"/>
</view>
</template>
<script>
import request,{host} from '@/common/request'
function setPickerCol(columns, value, n){
var v=value[0]||0
if(columns[v].item){
this.setColumnValues(n,columns[v].item)
setPickerCol(columns[v].item, value.slice(1), ++n)
}
}
export default{
props:{
label:{
@ -261,6 +277,15 @@ import request,{host} from '@/common/request'
imgList:[],
}
},
watch:{
columns(n){
if(this.type=='select'){
this.$nextTick(()=>{
setPickerCol.bind(this.$refs.picker)(n[0]||[],this.value,1)
})
}
},
},
computed:{
date(){
if(this.dateType=='start')return this.value[0]||new Date().format('yyyy-MM-dd');
@ -273,10 +298,15 @@ import request,{host} from '@/common/request'
if(this.type=='dateRange' && this.dateType=='end' && this.value[0])return new Date(this.value[0]).getTime();
},
imgs(){
if(this.type=='upImg')return this.value.map((v,index)=>({url:`${host(null,"/sys/common/static")}/${v}`,status:"success",index,type:'saved'})).concat(this.imgList.map((v,index)=>Object.assign(v,{index,type:'unsaved'})))
if(this.type=='upImg')return this.value.map((v,index)=>({url:`${host(undefined,"/plant_manage/sys/common/static")}/${v}`,status:"success",index,type:'saved'})).concat(this.imgList.map((v,index)=>Object.assign(v,{index,type:'unsaved'})))
return []
}
},
created(){
if(this.type=='select'){
window.the=this
}
},
methods:{
async afterRead(e){
this.imgList=this.imgList.concat(e.file.map(v=>Object.assign(v,{
@ -312,6 +342,11 @@ import request,{host} from '@/common/request'
}
this.$emit('imgs',this.imgs.map(v=>({saved:v.url,unsaved:v.tempUrl})[v.type]).join(','))
},
pickerChange(e){
if(e.value[e.columnIndex].item){
this.$refs.picker.setColumnValues(e.columnIndex+1,e.value[0].item)
}
},
},
}
</script>

9
pages/home/index.vue

@ -335,11 +335,13 @@ import request from '@/common/request.js'
},
onLoad() {
this.getMassif()
this.getPurchase()
},
onShow(){
},
methods: {
//
async getMassif(){
var res=await request("/api/plantIndex/queryPlot",{
params:{companyId: this.$store.getters.userInfo.companyId}
@ -353,7 +355,12 @@ import request from '@/common/request.js'
showCancel:false,
})
}
}
},
//
async getPurchase(){
var res=await request("/purchaseMain/purchaseMain/listPlantPurchaseSubByMainId")
console.log(res,'------------res----------')
},
}
}
</script>

48
pages/massif/detail.vue

@ -45,9 +45,10 @@
.detail{
background:#F7F7F7;
border-radius: 24rpx;
padding:30rpx;
padding:20rpx;
color:#999;
font-size:28rpx;
width:100%;
}
}
}
@ -59,42 +60,63 @@
<view class="title">基本信息</view>
<view class="item">
<text>基地名称</text> <text>A122323</text>
<text>基地名称</text> <text>{{detail.plantBaseName}}</text>
</view>
<view class="item">
<text>地块编号</text> <text>东方红壹号基地</text>
<text>地块编号</text> <text>{{detail.plotNumber}}</text>
</view>
<view class="item">
<text>地块面积</text> <text>45</text>
<text>地块面积</text> <text>{{detail.drawArea}}</text>
</view>
<view class="item">
<text>实际面积</text> <text>44</text>
<text>实际面积</text> <text>{{detail.realityArea}}</text>
</view>
<view class="item inline">
<text>地块图片</text>
<view class="imgs">
<image src="https://tse2-mm.cn.bing.net/th/id/OIP-C.0lguFbeN1p3XPMcmThvShwHaEO?w=281&h=180&c=7&r=0&o=5&pid=1.7"/>
<image src="https://tse2-mm.cn.bing.net/th/id/OIP-C.0lguFbeN1p3XPMcmThvShwHaEO?w=281&h=180&c=7&r=0&o=5&pid=1.7"/>
<image src="https://tse2-mm.cn.bing.net/th/id/OIP-C.0lguFbeN1p3XPMcmThvShwHaEO?w=281&h=180&c=7&r=0&o=5&pid=1.7"/>
<image mode="aspectFill" v-for="(v,k) in detail.image" :key="k" :src="`${imgUrl}/${v}`"/>
</view>
</view>
<view class="item">
<text>使用日期</text> <text>2021-10-15 2026-12-23</text>
<text>使用日期</text> <text>{{detail.beginTime}} {{detail.endTime}}</text>
</view>
<view class="item">
<text>经纬度</text> <text>东经97°31,北纬21°8</text>
</view>
<view class="item inline">
<text>详细地址</text>
<view class="detail">
这里是地址信息这里是地址信息这里是地址信息这里是地址信息
</view>
<view class="detail"> {{detail.address}} </view>
</view>
</view>
</view>
</template>
<script>
import request,{host} from '@/common/request'
export default{
data(){
return{
detail:{},
imgUrl:host(undefined,"/plant_manage/sys/common/static"),
}
},
onLoad(options){
this.getDetail(options.id)
},
methods:{
async getDetail(id){
var res=await request('/api/plantPlot/queryById',{
params:{id}
})
if(res.statu){
this.detail=res.data
}else{
uni.showModal({
title:"提示",
content:res.msg||"获取详情失败!",
showCancel:false,
})
}
}
}
}
</script>

20
pages/massif/index.vue

@ -83,7 +83,7 @@
<d-search v-model="searchVal.search" @search="clean();search()"/>
<scroll-view scroll-y @scrolltolower="search">
<view class="card item" v-for="(v,k) in list" :key="k" @click="$u.route({url:'pages/massif/detail'})">
<view class="card item" v-for="(v,k) in list" :key="k" @click="$u.route({url:'pages/massif/detail',params:{id:v.id}})">
<image src="https://ts1.cn.mm.bing.net/th?id=OIP-C.wc_dCG_KbIKZwMdtD3gL2QHaEt&w=313&h=199&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2"/>
<view class="info">
<view class="title">{{v.plotName}} <text class="plant-youbian"/></view>
@ -93,9 +93,9 @@
<text>{{v.usedArea}}</text> <text>(在用面积)</text>
</view>
<view class="btns">
<text class="plant-xiugai" @click.stop="$u.route({url:'/pages/massif/info',params:{id:v.id}})">修改</text>
<text class="plant-xiugai" @click.stop="reDetail(v.id)">修改</text>
<text class="plant-shanchu" @click.stop="del(k)">删除</text>
<text class="plant-xinzeng" @click.stop="$u.route({url:'pages/massif/mana/index'})">地块管理</text>
<text class="plant-xinzeng" @click.stop="$u.route({url:'pages/massif/mana/index',params:{id:v.id}})">地块管理</text>
</view>
</view>
</view>
@ -125,12 +125,14 @@ import request from '@/common/request'
toInfo(){
uni.navigateTo({
url:"/pages/massif/info",
events:{
update:()=>{
this.clean()
this.search()
}
},
events:{update:()=>{ this.clean();this.search() }}
})
},
//
reDetail(id){
uni.navigateTo({
url:`/pages/massif/info?id=${id}`,
events:{update:()=>{ this.clean();this.search() }}
})
},
clean(){

12
pages/massif/info.vue

@ -17,7 +17,7 @@
:value="(/^dateRange$|^select$/.test(v.type)?fields[k].value:formData[k])"
@input="formData[k]=$event"
@selectRDate="selectDate"
@select="fields[k].value=$event;formData[k]=fields[k].columns[0][$event].value"
@select="fields[k].value=[$event];formData[k]=fields[k].columns[0][$event].value"
@imgs="fields[k].value=$event"/>
</u-form>
<button class="cu-btn round bg-green shadow submit" @click="sumbit">保存</button>
@ -25,18 +25,16 @@
</template>
<script>
import request from '@/common/request'
import dForm from '@/components/form.vue'
export default{
components:{dForm},
data(){
return{
fields:{
plantBaseName:{label:"基地名称",type:"select",columns:[],value:''},
plantBaseName:{label:"基地名称",type:"select",columns:[],value:[null]},
plotNumber:{label:"地块编号"},
plotName:{label:"地块名称"},
drawArea:{label:"地块面积(亩)",type:'digit'},
realityArea:{label:"实际面积",type:'digit'},
image:{label:"地块图片",type:"upImg",num:3,value:[]},
image:{label:"地块图片",type:"upImg",num:3,value:''},
date:{label:"使用日期",type:"dateRange",value:[]},
jw:{label:"经/纬度"},
address:{label:"详细地址",type:"textarea"},
@ -84,7 +82,7 @@ import dForm from '@/components/form.vue'
params:{companyId:this.$store.getters.userInfo.companyId}
})
if(res.statu){
this.$set(this.fields.plantBaseName, "columns", [res.data.map(v=>({label:v,value:v}))])
this.fields.plantBaseName.columns = [res.data.map(v=>({label:v,value:v}))]
}else{
uni.showModal({
title:"提示",
@ -131,6 +129,8 @@ import dForm from '@/components/form.vue'
if(res.statu){
this.formData=res.data
this.fields.date.value=[res.data.beginTime, res.data.endTime]
this.fields.plantBaseName.value=this.fields.plantBaseName.columns[0].findIndex(v=>v.value==res.data.plantBaseName)
this.fields.image.value=res.data.image.join(',')
}else{
uni.showModal({
title:"提示",

8
pages/massif/mana/index.vue

@ -20,7 +20,7 @@
<u-tabs :list="tabs" :current="tabIndex" activeStyle="color:#10C176;" lineColor="#10C176" lineWidth="50" :scrollable="false" @change="tabIndex=$event.index"/>
<plant-plan v-if="tabIndex==0"/>
<plant-plan v-if="tabIndex==0" :id="plantId"/>
<farmRecord v-else-if="tabIndex==1" />
<recovery v-else />
</view>
@ -38,8 +38,12 @@ export default {
{name:"种植计划",},
{name:"农事记录",},
{name:"采收记录",},
]
],
plantId:"",
}
},
onLoad(options){
this.plantId=options.id
},
}
</script>

52
pages/massif/mana/plantPlan.vue

@ -89,33 +89,71 @@
</style>
<template>
<view class="plant_plan">
<view class="card">
<view class="card" v-for="(v,k) in list" :key="k">
<view class="info">
<image src="/static/logo.png"/>
<view class="detail">
<view class="name">
<text>无公害</text> <text>精品小黄瓜</text> <text class="plant-youbian"/>
<text>{{v.plantStandard}}</text> <text>{{v.varietyName}}</text> <text class="plant-youbian"/>
</view>
<view class="batch" style="--c:#999;">种植批次号A000001</view>
<view class="recovery" style="--c:#FFC760;">已采收xxxkg</view>
<view class="mu">45</view>
<view class="batch" style="--c:#999;">种植批次号{{v.plantBatch}}</view>
<view class="recovery" style="--c:#FFC760;">已采收{{v.harvested}}kg</view>
<view class="mu">{{v.plantArea}}</view>
</view>
</view>
<view class="date">
<text>本次预估采收时间2022-12-12</text>
<text>本次预估采收时间{{v.harvestTime}}</text>
<button class="cu-btn" style="--c:255, 196, 87;">结束种植</button>
<button class="cu-btn" style="--c:153, 153, 153;" @click="$u.route({url:'pages/massif/plant_info'})">采收</button>
</view>
</view>
<u-empty v-if="list.length==0" icon="http://cdn.uviewui.com/uview/empty/data.png"/>
<button class="cu-btn round bg-green shadow submit" @click="$u.route({url:'pages/massif/plant_plan'})">+新增种植计划</button>
</view>
</template>
<script>
import request from '@/common/request'
export default {
name:"plantPlan",
props:{
id:{
type:String,
default:""
}
},
data(){
return{
searchVal:{
pageNo:1,
pageSize:4
},
total:0,
list:[]
}
},
created(){
this.search()
},
methods:{
async search(){
if(this.total==0||this.list.length<this.total){
var res=await request('/api/plantPlan/list',{
params: {
...this.searchVal,
plotId: this.id
}
})
if(res.statu){
this.list=this.list.concat(res.data.records)
this.total=res.data.total
}else{
uni.showModal({
title:"提示",
content:res.msg||"获取地块列表失败!",
showCancel:false,
})
}
}
}
}
}

66
pages/massif/plant_plan.vue

@ -12,48 +12,84 @@
</style>
<template>
<view class="container">
<u-form class="card inline" :model="formData" :rules="rules" labelWidth="auto">
<u-form class="card inline" errorType="toast" :model="formData" :rules="rules" labelWidth="auto">
<d-form
v-for="(v,k) in fields"
:key="k"
v-bind="v"
:field="k"
:required="!!rules[k]"
@select="select"/>
:value="/^select$/.test(v.type)?fields[k].value:formData[k]"
@select="select"
@input="formData[k]=$event"
@imgs="fields[k].value=$event"/>
</u-form>
<button class="cu-btn round bg-green shadow submit">确认提交</button>
</view>
</template>
<script>
import request from '@/common/request'
export default {
data(){
return{
fields:{
name:{label:"品种名称"},
type:{label:"作物类型"},
area:{label:"种植面积(亩)"},
startDate:{label:"种植开始日期",type:"calendar"},
recoveryDate:{label:"预估采收日期",type:"calendar"},
imgs:{label:"产品图片",type:"upImg"},
standard:{label:"种植标准",type:"checkBox",columns:[
varietyName:{label:"品种名称"},
plantType:{label:"作物类型",type:"select",columns:[],value:[1,0]},
plantArea:{label:"种植面积(亩)",type:"digit"},
startTime:{label:"种植开始日期",type:"calendar"},
harvestTime:{label:"预估采收日期",type:"calendar"},
images:{label:"产品图片",type:"upImg",num:3,value:''},
plantStandard:{label:"种植标准",type:"radio",columns:[
{label:"有机",value:'1'},
{label:"绿色",value:'2'},
{label:"无公害",value:'3'},
{label:"普通",value:'4'},
]},
batch:{label:"种植批次号"},
director:{label:"负责人"},
identity:{label:"负责人身份证"},
intro:{label:"产品介绍",type:"textarea"},
plantBatch:{label:"种植批次号"},
principal:{label:"负责人"},
principalId:{label:"负责人身份证"},
productIntroduce:{label:"产品介绍",type:"textarea"},
},
formData:{name:""},
formData:{
varietyName:"",
plantType:"",
plantArea:"",
startTime:"",
harvestTime:"",
images:[],
plantStandard:"",
plantBatch:"",
principal:"",
principalId:"",
productIntroduce:"",
},
rules:{
varietyName: {required:true, message:"必填!", trigger:"blur"},
plantType: {required:true, message:"必填!", trigger:"blur"},
plantArea: {required:true, message:"必填!", trigger:"blur"},
startTime: {required:true, message:"必填!", trigger:"blur"},
harvestTime: {required:true, message:"必填!", trigger:"blur"},
images: {required:true, message:"必填!", trigger:"blur"},
plantStandard: {required:true, message:"必填!", trigger:"blur"},
plantBatch: {required:true, message:"必填!", trigger:"blur"},
principal: {required:true, message:"必填!", trigger:"blur"},
principalId: {required:true, message:"必填!", trigger:"blur"},
},
}
},
onLoad(){
this.init()
setTimeout(() => {
this.fields.plantType.columns=[[{label:"1",value:1,item:[{label:'1-1',value:'1-1'}]},{label:2,value:2,item:[{label:'2-1',value:'2-1'}]}]]
}, 1000);
},
methods:{
async init(){
var res=await request("/sys/category/loadTreeData",{
params:{pid:"",pcode:"B06",}
})
},
select(e){
console.log(e,'-------------e-----------------')
}

37
pages/purchase/agrProdList.vue

@ -46,9 +46,9 @@
<text slot="right" class="plant-xinjian" @click="$u.route({url:'pages/purchase/newAgr'})"/>
</cu-navbar>
<d-search/>
<d-search v-model="searchVal.goodsName" @search="search"/>
<view class="card" @click="$u.route({url:'pages/purchase/specs'})">
<view class="card" v-if="(v,k) in list" :key="k" @click="$u.route({url:'pages/purchase/specs'})">
<view class="name">
<text>化肥</text> 中量元素水溶肥 <text class="plant-youbian"/>
</view>
@ -59,7 +59,38 @@
</view>
</template>
<script>
import request from '@/common/request'
export default {
data(){
return{
searchVal:{
goodsName:"",
pageNo:1,
pageSize:5,
},
list:[],
total:0,
}
},
onLoad(){
this.search()
},
methods:{
async search(){
var res=await request("/api/goods/goodsList",{
params: this.searchVal
})
if(res.statu){
this.list=this.list.concat(res.data.records)
this.total=res.data.total
}else{
uni.showModal({
title:"提示",
content:res.msg||"获取农资列表失败!",
showCancel:false,
})
}
}
}
}
</script>

21
pages/purchase/apply.vue

@ -129,7 +129,26 @@
</view>
</template>
<script>
import request from '@/common/request'
export default {
data(){
return{
}
},
onLoad(){
this.init()
},
methods:{
async init(){
//
var res=await request("/api/purchase/purchaseUserShow")
if(res.statu){
}else{
}
}
}
}
</script>

11
pages/purchase/specs.vue

@ -149,7 +149,18 @@
</view>
</template>
<script>
import request from '@/common/request'
export default{
data(){
return{
}
},
onLoad(){},
methods:{
async init(){
var res=await request("")
}
}
}
</script>

0
uni_modules/d-search/changelog.md

45
uni_modules/d-search/components/d-search/d-search.vue

@ -0,0 +1,45 @@
<style lang="scss" scoped>
.d-search{
flex-shrink: 0;
display:flex;
align-items: center;
background:#fff;
margin:30rpx;
border-radius: 40rpx;
padding:6rpx;
height:60rpx;
.u-icon{
margin:0 14rpx;
flex-shrink: 0;
}
input{
flex-grow: 1;
}
.u-button{
flex-shrink: 0;
width:max-content;
}
}
</style>
<template>
<view class="d-search">
<u-icon name="search" color="#999999" size="20"/>
<input placeholder="请输入搜索内容" :value="value" @input="$emit('input',$event.detail.value)" @confirm="$emit('search')"/>
<u-button type="primary" shape="circle" color="#10C176" text="搜索" size="mini" @click="$emit('search')"/>
</view>
</template>
<script>
export default {
props:{
value:{
type:String,
default:""
}
},
data(){
return{
}
}
}
</script>

81
uni_modules/d-search/package.json

@ -0,0 +1,81 @@
{
"id": "d-search",
"displayName": "d-search",
"version": "1.0.0",
"description": "d-search",
"keywords": [
"d-search"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u"
},
"client": {
"Vue": {
"vue2": "u",
"vue3": "u"
},
"App": {
"app-vue": "u",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

1
uni_modules/d-search/readme.md

@ -0,0 +1 @@
# d-search

8
uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue

@ -1,12 +1,12 @@
<template>
<view class="uni-calendar">
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="close"></view>
<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}" @click.stop="">
<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
<view class="uni-calendar__header-btn-box" @click="close">
<view class="uni-calendar__header-btn-box" @click.stop="close">
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
</view>
<view class="uni-calendar__header-btn-box" @click="confirm">
<view class="uni-calendar__header-btn-box" @click.stop="confirm">
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
</view>
</view>

Loading…
Cancel
Save