mrr.sj.front/pages/shop/add-img-text.vue

483 lines
13 KiB
Vue
Raw Normal View History

2026-03-24 11:45:13 +08:00
<template>
<view class="addTextAndImg">
<custom-navbar title="添加图文" :show-back="true"></custom-navbar>
<view class="firstAdd" v-if="list.length == 0">
<view class="firstAdd-garden" @click="showPop = true">
<image src="/static/images/shop/imgAndText/add.png" mode="widthFix" class="firstAdd-garden-img"></image>
</view>
<view class="firstAdd-text">快来添加内容介绍你的服务吧</view>
</view>
<view v-else class="addTextAndImg-content">
<view v-for="(item, index) in list" :key="index" class="addTextAndImg-content-card">
<!-- <rich-text :nodes="item.value" v-if="item.type==1"></rich-text> -->
<uv-divider dashed v-if="item.type == 1" ></uv-divider>
<view class="addTextAndImg-content-card-text" v-if="item.type==2">{{ item.value }}</view>
<image style="width: 100%;" mode="widthFix" :src="item.value" v-else-if="item.type==3|| item.type==4"></image>
<view class="addTextAndImg-content-card-btns">
<view class="addTextAndImg-content-card-btns-btn" v-for="item2 in btns" :key="item2.id"
@click.stop="handleCard(item2.id, index)" v-if="
!(index == 0 && item2.id == 2) &&
!(index == list.length - 1 && item2.id == 3)
">
{{ item2.text }}
</view>
</view>
</view>
</view>
<view class="bottom-buttons" v-if="list.length != 0">
<button class="btn-submit" @click="submitForm">保存</button>
</view>
<uv-overlay :show="showPop" @click="showPop = false">
<view class="pop-cards">
<view class="pop-cards-card" v-for="item in addWays" :key="item.id" @click.stop="addContent(item.id)">
<image :src="item.url" class="pop-cards-card-img"></image>
<view class="pop-cards-card-text">
{{ item.text }}
</view>
</view>
<view class="pop-cards-close"> </view>
</view>
</uv-overlay>
<uv-overlay :show="showTextarea" @click="setTextarea">
<view class="pop-textarea" @tap.stop>
<textarea maxlength="-1" fixed="true" style="width: 100%;" v-model="textareaValue" />
</view>
</uv-overlay>
<!-- 获取权限提示匡内容 -->
<view class="permission" :class="{ transform: isShowPer && nowQer === 'xc' }">
<view class="per-tit">美融融plus 对储存空间/照片权限申请说明</view>
<view class="per-cont">便于您使用该功能上传您的照片/图片/视频以及用于更换头像发布商品等场景中读取相册和文件内容</view>
</view>
<view class="permission" :class="{ transform: isShowPer && nowQer === 'xj' }">
<view class="per-tit">美融融plus 对相机拍摄权限申请说明</view>
<view class="per-cont">便于您使用该功能上传您的照片/图片/视频以及用于更换头像发布商品等场景中所需内容</view>
</view>
</view>
</template>
<script>
import uploadImage from '../../utils/uploadImage'
import permissionUtils from '../../utils/per'
import locationService from '../../utils/locationService';
export default {
data() {
return {
isReplace:false,
crIndex: null, //插入位置
nowQer: 'xc',
isShowPer: false,
list: [],
textareaValue: "",
showPop: false,
showTextarea: false,
addWays: [{
text: "分割线",
id: 1,
url: "/static/images/shop/imgAndText/fenge.png",
},
{
text: "文本",
id: 2,
url: "/static/images/shop/imgAndText/text.png",
},
{
text: "图片",
id: 3,
url: "/static/images/shop/imgAndText/bz.png",
},
{
text: "相机",
id: 4,
url: "/static/images/shop/imgAndText/camera.png",
},
],
btns: [{
text: "删除",
id: 1,
},
{
text: "上移",
id: 2,
},
{
text: "下移",
id: 3,
},
{
text: "替换",
id: 4,
},
{
text: "插入",
id: 5,
},
],
};
},
onLoad(options) {
console.log(options)
if(options.list){
this.list = JSON.parse(options.list)
console.log(this.list)
}
},
methods: {
submitForm(){
uni.$emit('updateGraphicDetails', this.list);
uni.navigateBack()
},
// 定义一个函数,在数组的指定索引后插入数据
insertAfterIndex(arr, index, data) {
// 检查索引是否有效
if (index < 0 || index >= arr.length) {
console.error("索引无效");
return arr;
}
// 使用splice方法在index + 1的位置插入数据
// 第二个参数0表示不删除任何元素后面的参数是要插入的数据
arr.splice(index + 1, 0, data);
this.crIndex = null
return arr;
},
// 定义一个函数,替换数组指定索引处的数据
replaceAtIndex(arr, index, data) {
// 检查索引是否有效有效索引范围0 <= index < arr.length
if (index < 0 || index >= arr.length) {
console.error("索引无效");
return arr; // 索引无效时返回原数组
}
// 直接替换指定索引处的数据
arr[index] = data;
// 保持与插入方法一致的业务逻辑如果crIndex是你的业务变量
this.crIndex = null;
this.isReplace = false
return arr; // 返回修改后的数组
},
//写入文本
setTextarea() {
let obj = {
value: this.textareaValue,
type: 2,
};
if (this.textareaValue.length == 0) {
this.showTextarea = false
this.crIndex = null
return
}
if (this.crIndex!=null) {
if(this.isReplace){
this.replaceAtIndex(this.list, this.crIndex, obj);
}else{
this.insertAfterIndex(this.list, this.crIndex, obj);
}
} else {
this.list.push(obj);
}
this.textareaValue = ""
this.showTextarea = false
},
//操作卡片 删除,上移等
handleCard(id, index) {
switch (id) {
case 1:
this.list.splice(index, 1); // 从索引 index 开始,删除 1 个元素
this.showPop = false
break;
case 2:
// 保存要交换的两个元素
let temp = this.list[index - 1];
// 用 splice 交换:先替换 index-1 位置为 index 的值,再替换 index 位置为 temp
this.list.splice(index - 1, 1, this.list[index]); // 把 index-1 位置换成 index 的值
this.list.splice(index, 1, temp); // 把 index 位置换成原来 index-1 的值
break;
case 3:
// 保存要交换的两个元素
let temp2 = this.list[index + 1];
// 用 splice 交换:先替换 index-1 位置为 index 的值,再替换 index 位置为 temp
this.list.splice(index + 1, 1, this.list[index]); // 把 index-1 位置换成 index 的值
this.list.splice(index, 1, temp2); // 把 index 位置换成原来 index-1 的值
break;
case 4:
this.crIndex = index
this.isReplace = true
this.showPop = true
break;
case 5:
this.crIndex = index
this.showPop = true
}
},
addContent(id) {
switch (id) {
case 1:
let obj = {
value: ``,
type: 1,
};
if (this.crIndex!=null) {
if(this.isReplace){
this.replaceAtIndex(this.list, this.crIndex, obj);
}else{
this.insertAfterIndex(this.list, this.crIndex, obj);
}
} else {
this.list.push(obj);
}
this.showPop = false
break;
case 2:
this.showTextarea = true
this.showPop = false
break;
case 3:
this.chooseAvatar(3)
break;
case 4:
this.chooseAvatar(4)
}
},
async chooseAvatar(type) {
try {
const systemInfo = uni.getSystemInfoSync()
if(systemInfo.platform === 'ios') {
this.openCamera(type);
return
}
2026-03-25 13:29:04 +08:00
// 根据类型确定权限字符串和提示文本
const permissionKey = type === 3 ? 'photo_library' : 'camera';
const permissionAndroid = type === 3
? 'android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE'
: 'android.permission.CAMERA';
const dialogTitle = type === 3 ? '相册权限申请' : '相机权限申请';
const dialogContent = type === 3
? '我们需要访问您的相册以完成图片添加'
: '我们需要访问您的相机以完成图片拍摄';
const nowQer = type === 3 ? 'xc' : 'xj';
// 检查是否是首次请求(用于控制自定义视图显示)
const firstRequest = !plus.storage.getItem(`perm_${permissionKey}`);
2026-03-24 11:45:13 +08:00
if (firstRequest) {
this.isShowPer = true;
2026-03-25 13:29:04 +08:00
this.nowQer = nowQer;
2026-03-24 11:45:13 +08:00
}
2026-03-25 13:29:04 +08:00
// 1. 检查权限
const { granted } = await permissionUtils.checkPermission(permissionKey, dialogContent);
if (granted) {
this.isShowPer = false;
2026-03-24 11:45:13 +08:00
this.openCamera(type);
return;
}
2026-03-25 13:29:04 +08:00
// 2. 隐藏自定义视图,显示系统风格弹窗
this.isShowPer = false;
const confirm = await this.showPermissionDialog(dialogTitle, dialogContent);
2026-03-24 11:45:13 +08:00
if (!confirm) return;
2026-03-25 13:29:04 +08:00
// 3. 请求权限
const result = await permissionUtils.requestPermission(permissionKey, dialogContent);
2026-03-24 11:45:13 +08:00
if (result) {
this.openCamera(type);
} else {
locationService.openAppSettings();
}
} catch (error) {
console.error('权限处理出错:', error);
uni.showToast({
title: '权限检查失败',
icon: 'none'
});
}
},
// 显示权限说明弹窗
showPermissionDialog(title, content) {
return new Promise((resolve) => {
uni.showModal({
title,
content,
confirmText: '去开启',
success(res) {
resolve(res.confirm);
}
});
});
},
2026-03-25 13:29:04 +08:00
// 打开相机/相册
2026-03-24 11:45:13 +08:00
async openCamera(type) {
this.isShowPer = false;
let result = null
if (type == 3) {
result = await uploadImage.handleUpload(this.$store.state.sjInfo.id ? this.$store.state.sjInfo.id :
Math.floor(Math.random() * 1000), 1, ['album']);
} else {
result = await uploadImage.handleUpload(this.$store.state.sjInfo.id ? this.$store.state.sjInfo.id :
Math.floor(Math.random() * 1000), 1, ['camera']);
}
uni.hideLoading();
// this.userInfo.head_photo = result;
let obj = {
value: result,
type: type,
};
if (this.crIndex!=null) {
if(this.isReplace){
this.replaceAtIndex(this.list, this.crIndex, obj);
}else{
this.insertAfterIndex(this.list, this.crIndex, obj);
}
} else {
this.list.push(obj);
}
this.showPop = false
},
},
};
</script>
<style lang="less">
.addTextAndImg {
padding-bottom: 110rpx;
.firstAdd {
position: fixed;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
display: flex;
flex-wrap: wrap;
justify-content: center;
.firstAdd-garden {
width: 200rpx;
height: 200rpx;
border: 3px solid #000;
border-radius: 50%;
margin-bottom: 100rpx;
.firstAdd-garden-img{
width: 200rpx;
}
}
.firstAdd-text {
font-size: 32rpx;
text-align: center;
white-space: nowrap;
width: 750rpx;
}
}
.addTextAndImg-content {
.addTextAndImg-content-card {
.addTextAndImg-content-card-btns {
display: flex;
flex-wrap: nowrap;
justify-content: flex-end;
gap: 10rpx;
background: #f5f5f5;
padding-bottom: 10rpx;
.addTextAndImg-content-card-btns-btn {
color: rgba(232, 16, 30, 1);
border: 2rpx solid rgba(232, 16, 30, 1);
width: 80rpx;
height: 50rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.addTextAndImg-content-card-text {
padding: 20rpx;
}
}
}
.pop-cards {
z-index: 10;
position: absolute;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
display: flex;
flex-wrap: nowrap;
gap: 63rpx;
padding: 68rpx 40rpx;
.pop-cards-card {
.pop-cards-card-img {
width: 120rpx;
height: 120rpx;
}
.pop-cards-card-text {
font-weight: 400;
font-size: 28rpx;
color: #333333;
line-height: 40rpx;
text-align: center;
font-style: normal;
}
}
}
.pop-textarea {
background-color: #fff;
margin: 200rpx 20rpx 20rpx 20rpx;
border-radius: 20rpx;
padding: 20rpx;
}
}
.permission.transform {
top: calc(var(--status-bar-height) + 88rpx + 20rpx);
opacity: 1;
visibility: visible;
}
.bottom-buttons {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
height: 100rpx;
padding: 40rpx 0 64rpx;
box-sizing: border-box;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
.btn-submit {
background-color: rgba(232, 16, 30, 1);
color: #fff;
width: 334rpx;
height: 78rpx;
line-height: 78rpx;
text-align: center;
font-size: 28rpx;
border-radius: 78rpx;
}
}
</style>