Compare commits
3 Commits
560b214af4
...
6720c15e30
| Author | SHA1 | Date | |
|---|---|---|---|
| 6720c15e30 | |||
| 2860c46ec1 | |||
| 47d10945a6 |
@@ -93,9 +93,9 @@
|
||||
"updateSentGroupApplition",
|
||||
]),
|
||||
init(){
|
||||
//uni.setStorageSync('BusinessToken','eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ3ZWJtYW4udGlueXdhbi5jbiIsImF1ZCI6IndlYm1hbi50aW55d2FuLmNuIiwiaWF0IjoxNzY4OTc4OTQ1LCJuYmYiOjE3Njg5Nzg5NDUsImV4cCI6MTc2OTU4Mzc0NSwiZXh0ZW5kIjp7ImlkIjoxMDAwMjgsInVzZXJuYW1lIjoiMTgxMDgxNDQwNDEiLCJjbGllbnQiOiJXRUIifX0.XH6qlb0D_9jpvlSxKM_w6a8Nl8fZPwkdq_b8zzOS2mY');
|
||||
//uni.setStorageSync('IMToken','eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOiIxMDAwMjgiLCJQbGF0Zm9ybUlEIjoyLCJleHAiOjE3NzY3NTQ5NDUsImlhdCI6MTc2ODk3ODk0MH0.tT1S-Rdcd1NS33vQ9S_-5c55WrlyOiL-gxOGHOPo_zA');
|
||||
//uni.setStorageSync('IMUserID','100028');
|
||||
//uni.setStorageSync('BusinessToken','eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ3ZWJtYW4udGlueXdhbi5jbiIsImF1ZCI6IndlYm1hbi50aW55d2FuLmNuIiwiaWF0IjoxNzcwMTAyMjc2LCJuYmYiOjE3NzAxMDIyNzYsImV4cCI6MTc3MDcwNzA3NiwiZXh0ZW5kIjp7ImlkIjoxMDA3MDMsInVzZXJuYW1lIjoiMTg2MTE4ODI2MjMiLCJjbGllbnQiOiJXRUIifX0.yZ2u4cCZq2hLRAIpCKUs8GZkut7CObmfApIZGP_L2ro');
|
||||
//uni.setStorageSync('IMToken','eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOiJKTTZHMEVWMjVSIiwiUGxhdGZvcm1JRCI6MiwiZXhwIjoxNzc3ODc4Mjc2LCJpYXQiOjE3NzAxMDIyNzF9.rKWz00yCB36CexCahW-HhsFZfKIFcfkuOYLKApQWQT0 ');
|
||||
//uni.setStorageSync('IMUserID','JM6G0EV25R');
|
||||
const IMToken = uni.getStorageSync("IMToken");
|
||||
const IMUserID = uni.getStorageSync("IMUserID")+'';
|
||||
if (IMToken && IMUserID) {
|
||||
|
||||
+26
-4
@@ -129,17 +129,39 @@ export const upload = (files,data,onProgress) =>{
|
||||
onProgress = data;
|
||||
data = {};
|
||||
}
|
||||
data.data = data.data ? data.data : {};
|
||||
let headers = {};
|
||||
if(data.token){
|
||||
headers = data.headers;
|
||||
delete data.headers;
|
||||
}
|
||||
headers = {
|
||||
...headers,
|
||||
client:uni.getSystemInfoSync().osName,
|
||||
token:uni.getStorageSync("BusinessToken"),
|
||||
operationID: (Math.random() * 36).toString(36).slice(2) + new Date().getTime().toString(),
|
||||
// #ifdef APP-PLUS
|
||||
ClientVersion:plus.runtime.versionCode,
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
ClientVersion:350,
|
||||
// #endif
|
||||
}
|
||||
console.log(typeof files);
|
||||
let url = "/user/upload";
|
||||
if(data.url){
|
||||
url = data.url;
|
||||
delete data.url;
|
||||
}
|
||||
url= config.getRegisterUrl()+url;
|
||||
return new Promise((resolve,reject)=>{
|
||||
var u = uni.uploadFile({
|
||||
url: config.getRegisterUrl()+(data?.url || "/user/upload"),
|
||||
url: url,
|
||||
filePath: files,
|
||||
//files:files.length > 1 ? files : files[0],
|
||||
name: "file",
|
||||
formData:data,
|
||||
header:{
|
||||
token:uni.getStorageSync("BusinessToken"),
|
||||
},
|
||||
header:headers,
|
||||
success({data,errMsg}){
|
||||
console.log(data);
|
||||
data = JSON.parse(data);
|
||||
|
||||
+3
-9
@@ -4,15 +4,9 @@
|
||||
// const WS_URL = `ws://${BASE_HOST}:10001`
|
||||
|
||||
const BASE_DOMAIN = 'www.shun777.com'
|
||||
// const CHAT_URL = `https://${BASE_DOMAIN}/chat`
|
||||
// const API_URL = `https://${BASE_DOMAIN}/api`
|
||||
// const WS_URL = `wss://${BASE_DOMAIN}/msg_gateway`
|
||||
// const CHAT_URL = `http://${BASE_DOMAIN}/api`
|
||||
// const API_URL = `http://${BASE_DOMAIN}/imapi`
|
||||
// const WS_URL = `ws://${BASE_DOMAIN}/ws`
|
||||
const CHAT_URL = `http://103.39.222.184:8585/api`
|
||||
const API_URL = `http://103.39.222.184:10002`
|
||||
const WS_URL = `ws://103.39.222.184:10001`
|
||||
const CHAT_URL = `https://${BASE_DOMAIN}/api`
|
||||
const API_URL = `https://${BASE_DOMAIN}/imapi`
|
||||
const WS_URL = `wss://${BASE_DOMAIN}/msg_gateway`
|
||||
|
||||
const version = '2.0.6'
|
||||
|
||||
|
||||
@@ -0,0 +1,678 @@
|
||||
<template>
|
||||
<div class="cut-avatar-page" v-if="tempFilePath">
|
||||
<div class="main-content" v-if="1==2">
|
||||
<div class="preview-section">
|
||||
<div v-if="resultPath" class="result-box">
|
||||
<image :src="resultPath" mode="widthFix" class="result-image" @click="previewResult"></image>
|
||||
<div class="action-row">
|
||||
<button class="btn btn-outline" @click="reSelect">重新选择</button>
|
||||
<button class="btn btn-primary" @click="uploadImage">确认上传</button>
|
||||
</div>
|
||||
<text class="tip-text">点击图片可预览大图</text>
|
||||
</div>
|
||||
|
||||
<div v-else class="upload-box" @click="onSelect">
|
||||
<div class="placeholder-icon">+</div>
|
||||
<text class="upload-text">点击上传图片</text>
|
||||
<text class="upload-sub-text">支持 JPG/PNG,自动裁剪 1:1</text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="isShowEditor" class="editor-modal" :class="{ 'dark-mode': isDarkMode }">
|
||||
<div class="cropper-wrapper">
|
||||
<movable-area class="crop-area" :style="{ height: screenHeight + 'px' }">
|
||||
<movable-view
|
||||
class="crop-view"
|
||||
direction="all"
|
||||
:out-of-bounds="true"
|
||||
:x="imgX"
|
||||
:y="imgY"
|
||||
:scale="scale+''"
|
||||
:scale-min="0.5"
|
||||
:scale-max="4"
|
||||
:animation="false"
|
||||
@change="onMoveChange"
|
||||
@scale="onScaleChange"
|
||||
:style="{ width: imgDisplayWidth + 'px', height: imgDisplayHeight + 'px' }"
|
||||
>
|
||||
<image :src="tempFilePath" class="target-image" :style="{ transform: 'rotate(' + rotation + 'deg)' }"></image>
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
|
||||
<div class="mask-layer" :style="{ height: screenHeight + 'px' }">
|
||||
<div class="mask-top" :style="{ height: (screenHeight - cropSize) / 2 + 'px' }"></div>
|
||||
<div class="mask-middle" :style="{ height: cropSize + 'px' }">
|
||||
<div class="mask-left" :style="{ width: (screenWidth - cropSize) / 2 + 'px' }"></div>
|
||||
<div class="crop-box" :style="{ width: cropSize + 'px', height: cropSize + 'px' }">
|
||||
<div class="corner c-tl"></div>
|
||||
<div class="corner c-tr"></div>
|
||||
<div class="corner c-bl"></div>
|
||||
<div class="corner c-br"></div>
|
||||
</div>
|
||||
<div class="mask-right" :style="{ width: (screenWidth - cropSize) / 2 + 'px' }"></div>
|
||||
</div>
|
||||
<div class="mask-bottom" :style="{ height: (screenHeight - cropSize) / 2 + 'px' }"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor-toolbar">
|
||||
<div class="tool-btn" @click="onCancel">取消</div>
|
||||
<div class="tool-btn" @click="onReset"> <text class="icon-reset">↻</text> 重置 </div>
|
||||
<div class="tool-btn" @click="onRotate"> <text class="icon-rotate">↻</text> 旋转 </div>
|
||||
<div class="tool-btn btn-confirm" @click="onConfirm">确定</div>
|
||||
</div>
|
||||
|
||||
<canvas canvas-id="cropCanvas" class="crop-canvas" :style="{ width: cropSize + 'px', height: cropSize + 'px' }"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 核心逻辑说明:
|
||||
* 1. 使用 movable-view 实现用户手势交互(拖拽、缩放)。
|
||||
* 2. 使用 image 的 css transform 实现视觉上的旋转。
|
||||
* 3. 最终生成时,通过计算偏移量,使用 CanvasContext 绘制图像。
|
||||
* 4. 旋转后的 Canvas 绘图坐标系需要特殊处理 (translate + rotate)。
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// --- 系统/环境参数 ---
|
||||
screenWidth: 375,
|
||||
screenHeight: 600,
|
||||
isDarkMode: false,
|
||||
|
||||
// --- 业务数据 ---
|
||||
resultPath: '', // 最终生成的图片路径
|
||||
|
||||
// --- 编辑器状态 ---
|
||||
isShowEditor: false,
|
||||
tempFilePath: '', // 选中的原始图片路径
|
||||
|
||||
// --- 图片原始信息 ---
|
||||
realImgWidth: 0,
|
||||
realImgHeight: 0,
|
||||
|
||||
// --- 交互状态数据 ---
|
||||
cropSize: 280, // 裁剪框大小 (正方形)
|
||||
imgDisplayWidth: 0, // 图片在屏幕上的初始显示宽度
|
||||
imgDisplayHeight: 0, // 图片在屏幕上的初始显示高度
|
||||
|
||||
// movable-view 的属性
|
||||
imgX: 0,
|
||||
imgY: 0,
|
||||
scale: 1,
|
||||
rotation: 0, // 0, 90, 180, 270
|
||||
|
||||
// 记录移动过程中的临时数据 (用于计算)
|
||||
currentX: 0,
|
||||
currentY: 0,
|
||||
currentScale: 1,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.initSystemInfo();
|
||||
},
|
||||
methods: {
|
||||
// -----------------------------------------------------------
|
||||
// 初始化与系统适配
|
||||
// -----------------------------------------------------------
|
||||
initSystemInfo() {
|
||||
const sys = uni.getSystemInfoSync();
|
||||
this.screenWidth = sys.windowWidth;
|
||||
this.screenHeight = sys.windowHeight;
|
||||
|
||||
// 适配暗黑模式
|
||||
if (sys.theme === 'dark') {
|
||||
this.isDarkMode = true;
|
||||
}
|
||||
|
||||
// 动态计算裁剪框大小 (屏幕宽度的 80%,最大 400px 用于适配 Pad)
|
||||
let size = this.screenWidth * 0.8;
|
||||
if (size > 400) size = 400;
|
||||
this.cropSize = Math.floor(size);
|
||||
},
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// 交互逻辑
|
||||
// -----------------------------------------------------------
|
||||
onSelect() {
|
||||
console.log('[Debug] 点击选择图片');
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['original', 'compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const src = res.tempFilePaths[0];
|
||||
this.enterEditor(src);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[Error] 选择图片失败', err);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
reSelect() {
|
||||
this.onSelect();
|
||||
},
|
||||
|
||||
previewResult() {
|
||||
if (this.resultPath) {
|
||||
uni.previewImage({
|
||||
urls: [this.resultPath],
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
uploadImage() {
|
||||
console.log('[Debug] 触发上传逻辑, 路径:', this.resultPath);
|
||||
// 这里预留上传 API 调用
|
||||
uni.showLoading({ title: '正在上传...' });
|
||||
setTimeout(() => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '模拟上传成功', icon: 'success' });
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// 编辑器逻辑
|
||||
// -----------------------------------------------------------
|
||||
|
||||
// 进入编辑模式,初始化图片位置
|
||||
enterEditor(src) {
|
||||
uni.showLoading({ title: '加载中...' });
|
||||
|
||||
uni.getImageInfo({
|
||||
src: src,
|
||||
success: (res) => {
|
||||
this.tempFilePath = src;
|
||||
this.realImgWidth = res.width;
|
||||
this.realImgHeight = res.height;
|
||||
|
||||
// 重置状态
|
||||
this.rotation = 0;
|
||||
this.scale = 1;
|
||||
this.currentScale = 1;
|
||||
|
||||
// 计算图片初始显示尺寸(使其适应屏幕宽度,类似 width: 100%)
|
||||
// 这里我们让图片的短边至少填满裁剪框,方便用户操作
|
||||
const ratio = this.realImgWidth / this.realImgHeight;
|
||||
|
||||
if (ratio > 1) {
|
||||
// 横图:高度定为裁剪框大小 + 一点冗余,宽度自适应
|
||||
this.imgDisplayHeight = this.cropSize;
|
||||
this.imgDisplayWidth = this.imgDisplayHeight * ratio;
|
||||
} else {
|
||||
// 竖图
|
||||
this.imgDisplayWidth = this.cropSize;
|
||||
this.imgDisplayHeight = this.imgDisplayWidth / ratio;
|
||||
}
|
||||
|
||||
// 居中计算
|
||||
// 屏幕中心
|
||||
const centerX = this.screenWidth / 2;
|
||||
const centerY = this.screenHeight / 2;
|
||||
|
||||
// 计算 movable-view 的初始 x, y 使其居中
|
||||
// movable-view 的 x,y 是相对于 movable-area (全屏) 的左上角
|
||||
this.imgX = centerX - this.imgDisplayWidth / 2;
|
||||
this.imgY = centerY - this.imgDisplayHeight / 2;
|
||||
|
||||
// 同步 current 值
|
||||
this.currentX = this.imgX;
|
||||
this.currentY = this.imgY;
|
||||
|
||||
this.isShowEditor = true;
|
||||
uni.hideLoading();
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '图片加载失败', icon: 'none' });
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
onMoveChange(e) {
|
||||
// 记录移动位置,用于最终裁剪计算
|
||||
// detail: {x, y, source}
|
||||
this.currentX = e.detail.x;
|
||||
this.currentY = e.detail.y;
|
||||
},
|
||||
onReset(){
|
||||
this.rotation = 0;
|
||||
this.currentScale = 1;
|
||||
},
|
||||
onScaleChange(e) {
|
||||
// detail: {scale}
|
||||
this.currentScale = e.detail.scale;
|
||||
},
|
||||
|
||||
onRotate() {
|
||||
console.log('[Debug] 点击旋转');
|
||||
// 顺时针旋转 90 度
|
||||
this.rotation = (this.rotation + 90) % 360;
|
||||
// 旋转后,可能需要重置一下缩放或位置逻辑?
|
||||
// 本方案中,为了简化体验,仅做视觉旋转,
|
||||
// 最终 Canvas 裁剪时根据 rotation 参数处理坐标系。
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.isShowEditor = false;
|
||||
this.tempFilePath = '';
|
||||
},
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// 核心裁剪生成逻辑 (Canvas)
|
||||
// -----------------------------------------------------------
|
||||
// -----------------------------------------------------------
|
||||
onConfirm() {
|
||||
console.log('[Debug] 开始生成图片');
|
||||
uni.showLoading({ title: '处理中...' });
|
||||
|
||||
const ctx = uni.createCanvasContext('cropCanvas', this);
|
||||
|
||||
// 1. 基础参数
|
||||
const destSize = this.cropSize; // 画布大小 (正方形)
|
||||
const halfDest = destSize / 2;
|
||||
|
||||
// 清空画布
|
||||
ctx.setFillStyle('#FFFFFF');
|
||||
ctx.fillRect(0, 0, destSize, destSize);
|
||||
|
||||
// 2. 计算【屏幕坐标系】下的中心点偏移
|
||||
// 这里的逻辑是:找出"图片中心"相对于"裁剪框中心"在屏幕上的距离
|
||||
|
||||
// A. 裁剪框中心在屏幕上的坐标
|
||||
const cropCenterX = (this.screenWidth - this.cropSize) / 2 + this.cropSize / 2;
|
||||
const cropCenterY = (this.screenHeight - this.cropSize) / 2 + this.cropSize / 2;
|
||||
|
||||
// B. 图片中心在屏幕上的坐标
|
||||
// 注意:movable-view 的 x,y 是左上角坐标,且 movable-view 的缩放是以中心为原点的
|
||||
// 实际上 uni-app 的 movable-view 在缩放/移动后,x/y 会自动更新为当前的左上角位置
|
||||
// 所以图片中心 = 当前x + (显示宽度 * 缩放 / 2)
|
||||
const currentRealWidth = this.imgDisplayWidth * this.currentScale;
|
||||
const currentRealHeight = this.imgDisplayHeight * this.currentScale;
|
||||
|
||||
const imgCenterX = this.currentX + currentRealWidth / 2;
|
||||
const imgCenterY = this.currentY + currentRealHeight / 2;
|
||||
|
||||
// C. 算出屏幕偏移向量 (Screen Diff)
|
||||
// 含义:图片中心在裁剪框中心的 右侧 diffX 像素,下方 diffY 像素
|
||||
const diffX = imgCenterX - cropCenterX;
|
||||
const diffY = imgCenterY - cropCenterY;
|
||||
|
||||
// 3. 将屏幕偏移向量【映射】到旋转后的 Canvas 坐标系
|
||||
// 我们需要算出:在旋转后的坐标系里,图片中心应该在哪里 (drawX, drawY)
|
||||
let drawX = 0;
|
||||
let drawY = 0;
|
||||
|
||||
// 规范化旋转角度 (0, 90, 180, 270)
|
||||
const angle = this.rotation % 360;
|
||||
|
||||
// 坐标系映射逻辑:
|
||||
// 屏幕 X+ (向右),屏幕 Y+ (向下)
|
||||
// 假设 Canvas 原点已移至中心并旋转:
|
||||
switch (angle) {
|
||||
case 0:
|
||||
// 0度:坐标系一致
|
||||
drawX = diffX;
|
||||
drawY = diffY;
|
||||
break;
|
||||
case 90:
|
||||
// 90度 (顺时针):Canvas X轴指向屏幕下,Canvas Y轴指向屏幕左
|
||||
// 屏幕的 X+ (向右) 对应 Canvas 的 Y- (向左的相反) -> drawY = -diffX
|
||||
// 屏幕的 Y+ (向下) 对应 Canvas 的 X+ (向下) -> drawX = diffY
|
||||
drawX = diffY;
|
||||
drawY = -diffX;
|
||||
break;
|
||||
case 180:
|
||||
// 180度:Canvas X轴向左,Canvas Y轴向上 (完全相反)
|
||||
drawX = -diffX;
|
||||
drawY = -diffY;
|
||||
break;
|
||||
case 270: // 相当于 -90度
|
||||
// 270度:Canvas X轴向上,Canvas Y轴向右
|
||||
// 屏幕 X+ (向右) 对应 Canvas Y+ -> drawY = diffX
|
||||
// 屏幕 Y+ (向下) 对应 Canvas X- -> drawX = -diffY
|
||||
drawX = -diffY;
|
||||
drawY = diffX;
|
||||
break;
|
||||
}
|
||||
|
||||
// 4. 执行绘制
|
||||
ctx.save();
|
||||
|
||||
// a. 将原点移到画布中心
|
||||
ctx.translate(halfDest, halfDest);
|
||||
// b. 旋转坐标系
|
||||
ctx.rotate((angle * Math.PI) / 180);
|
||||
|
||||
// c. 绘制图片
|
||||
// drawImage 的 x,y 是图片的左上角坐标
|
||||
// 我们算出的 drawX, drawY 是图片中心相对于画布中心的坐标
|
||||
// 所以要减去宽高的一半
|
||||
ctx.drawImage(this.tempFilePath, drawX - currentRealWidth / 2, drawY - currentRealHeight / 2, currentRealWidth, currentRealHeight);
|
||||
|
||||
ctx.restore();
|
||||
|
||||
// 5. 导出图片
|
||||
ctx.draw(false, () => {
|
||||
setTimeout(() => {
|
||||
uni.canvasToTempFilePath(
|
||||
{
|
||||
canvasId: 'cropCanvas',
|
||||
width: destSize,
|
||||
height: destSize,
|
||||
fileType: 'jpg',
|
||||
quality: 1,
|
||||
success: (res) => {
|
||||
this.resultPath = res.tempFilePath;
|
||||
this.tempFilePath = "";
|
||||
this.isShowEditor = false;
|
||||
uni.hideLoading();
|
||||
this.$emit('save', {path:this.resultPath});
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '生成失败', icon: 'none' });
|
||||
},
|
||||
},
|
||||
this,
|
||||
);
|
||||
}, 200);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* ========================
|
||||
CSS 变量定义
|
||||
======================== */
|
||||
.cut-avatar-page {
|
||||
--primary-color: #ef3912;
|
||||
--bg-color: #f8f9fa;
|
||||
--text-color: #333333;
|
||||
--modal-bg: #000000;
|
||||
|
||||
min-height: 100vh;
|
||||
background-color: var(--bg-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 适配暗黑模式 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.page-container {
|
||||
--bg-color: #1a1a1a;
|
||||
--text-color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================
|
||||
主界面样式
|
||||
======================== */
|
||||
.nav-bar {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--bg-color);
|
||||
/* 简单的顶部阴影 */
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.preview-section {
|
||||
width: 100%;
|
||||
max-width: 600px; /* Pad 适配限制 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
/* 上传占位框 */
|
||||
.upload-box {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
border: 2px dashed #cccccc;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.02);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-box:active {
|
||||
background-color: rgba(239, 57, 18, 0.05);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.placeholder-icon {
|
||||
font-size: 40px;
|
||||
color: #999;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.upload-text {
|
||||
font-size: 16px;
|
||||
color: var(--text-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.upload-sub-text {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* 结果展示区 */
|
||||
.result-box {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.result-image {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
background-color: #eee;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.action-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-size: 14px;
|
||||
padding: 8px 24px;
|
||||
border-radius: 20px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background-color: transparent;
|
||||
border: 1px solid #ccc;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
/* ========================
|
||||
编辑器弹窗样式 (全屏)
|
||||
======================== */
|
||||
.editor-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999;
|
||||
background-color: #000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cropper-wrapper {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.crop-area {
|
||||
width: 100%;
|
||||
/* height 由 JS 动态控制 */
|
||||
}
|
||||
|
||||
.crop-view {
|
||||
/* 初始不可见,加载图片后显示 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.target-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* 优化图片渲染 */
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
/* 遮罩层布局 */
|
||||
.mask-layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
pointer-events: none; /* 让事件穿透到底下的 movable-area */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.mask-top,
|
||||
.mask-bottom,
|
||||
.mask-left,
|
||||
.mask-right {
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.mask-middle {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* 裁剪框样式 */
|
||||
.crop-box {
|
||||
position: relative;
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 四个角的装饰 */
|
||||
.corner {
|
||||
position: absolute;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
|
||||
.c-tl {
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
.c-tr {
|
||||
top: -2px;
|
||||
right: -2px;
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
.c-bl {
|
||||
bottom: -2px;
|
||||
left: -2px;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
}
|
||||
.c-br {
|
||||
bottom: -2px;
|
||||
right: -2px;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
/* 底部工具栏 */
|
||||
.editor-toolbar {
|
||||
height: 80px; /* 留足安全距离 */
|
||||
background-color: #1a1a1a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 30px;
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.tool-btn {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
color: var(--primary-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.icon-rotate {
|
||||
font-size: 18px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
/* Canvas 隐藏处理 */
|
||||
.crop-canvas {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
top: -9999px;
|
||||
pointer-events: none;
|
||||
visibility: hidden; /* 这里用 hidden, 有些环境 display:none 会导致不渲染 */
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启
|
||||
*/
|
||||
|
||||
var isIos
|
||||
// #ifdef APP-PLUS
|
||||
isIos = (plus.os.name == "iOS")
|
||||
// #endif
|
||||
|
||||
// 判断推送权限是否开启
|
||||
function judgeIosPermissionPush() {
|
||||
var result = false;
|
||||
var UIApplication = plus.ios.import("UIApplication");
|
||||
var app = UIApplication.sharedApplication();
|
||||
var enabledTypes = 0;
|
||||
if (app.currentUserNotificationSettings) {
|
||||
var settings = app.currentUserNotificationSettings();
|
||||
enabledTypes = settings.plusGetAttribute("types");
|
||||
console.log("enabledTypes1:" + enabledTypes);
|
||||
if (enabledTypes == 0) {
|
||||
console.log("推送权限没有开启");
|
||||
} else {
|
||||
result = true;
|
||||
console.log("已经开启推送功能!")
|
||||
}
|
||||
plus.ios.deleteObject(settings);
|
||||
} else {
|
||||
enabledTypes = app.enabledRemoteNotificationTypes();
|
||||
if (enabledTypes == 0) {
|
||||
console.log("推送权限没有开启!");
|
||||
} else {
|
||||
result = true;
|
||||
console.log("已经开启推送功能!")
|
||||
}
|
||||
console.log("enabledTypes2:" + enabledTypes);
|
||||
}
|
||||
plus.ios.deleteObject(app);
|
||||
plus.ios.deleteObject(UIApplication);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断定位权限是否开启
|
||||
function judgeIosPermissionLocation() {
|
||||
var result = false;
|
||||
var cllocationManger = plus.ios.import("CLLocationManager");
|
||||
var status = cllocationManger.authorizationStatus();
|
||||
result = (status != 2)
|
||||
console.log("定位权限开启:" + result);
|
||||
// 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation
|
||||
/* var enable = cllocationManger.locationServicesEnabled();
|
||||
var status = cllocationManger.authorizationStatus();
|
||||
console.log("enable:" + enable);
|
||||
console.log("status:" + status);
|
||||
if (enable && status != 2) {
|
||||
result = true;
|
||||
console.log("手机定位服务已开启且已授予定位权限");
|
||||
} else {
|
||||
console.log("手机系统的定位没有打开或未给予定位权限");
|
||||
} */
|
||||
plus.ios.deleteObject(cllocationManger);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断麦克风权限是否开启
|
||||
function judgeIosPermissionRecord() {
|
||||
var result = false;
|
||||
var avaudiosession = plus.ios.import("AVAudioSession");
|
||||
var avaudio = avaudiosession.sharedInstance();
|
||||
var permissionStatus = avaudio.recordPermission();
|
||||
console.log("permissionStatus:" + permissionStatus);
|
||||
if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
|
||||
console.log("麦克风权限没有开启");
|
||||
} else {
|
||||
result = true;
|
||||
console.log("麦克风权限已经开启");
|
||||
}
|
||||
plus.ios.deleteObject(avaudiosession);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断相机权限是否开启
|
||||
function judgeIosPermissionCamera() {
|
||||
var result = false;
|
||||
var AVCaptureDevice = plus.ios.import("AVCaptureDevice");
|
||||
var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
|
||||
console.log("authStatus:" + authStatus);
|
||||
if (authStatus == 3) {
|
||||
result = true;
|
||||
console.log("相机权限已经开启");
|
||||
} else {
|
||||
console.log("相机权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(AVCaptureDevice);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断相册权限是否开启
|
||||
function judgeIosPermissionPhotoLibrary() {
|
||||
var result = false;
|
||||
var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
|
||||
var authStatus = PHPhotoLibrary.authorizationStatus();
|
||||
console.log("authStatus:" + authStatus);
|
||||
if (authStatus == 3) {
|
||||
result = true;
|
||||
console.log("相册权限已经开启");
|
||||
} else {
|
||||
console.log("相册权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(PHPhotoLibrary);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断通讯录权限是否开启
|
||||
function judgeIosPermissionContact() {
|
||||
var result = false;
|
||||
var CNContactStore = plus.ios.import("CNContactStore");
|
||||
var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
|
||||
if (cnAuthStatus == 3) {
|
||||
result = true;
|
||||
console.log("通讯录权限已经开启");
|
||||
} else {
|
||||
console.log("通讯录权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(CNContactStore);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断日历权限是否开启
|
||||
function judgeIosPermissionCalendar() {
|
||||
var result = false;
|
||||
var EKEventStore = plus.ios.import("EKEventStore");
|
||||
var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
|
||||
if (ekAuthStatus == 3) {
|
||||
result = true;
|
||||
console.log("日历权限已经开启");
|
||||
} else {
|
||||
console.log("日历权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(EKEventStore);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断备忘录权限是否开启
|
||||
function judgeIosPermissionMemo() {
|
||||
var result = false;
|
||||
var EKEventStore = plus.ios.import("EKEventStore");
|
||||
var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
|
||||
if (ekAuthStatus == 3) {
|
||||
result = true;
|
||||
console.log("备忘录权限已经开启");
|
||||
} else {
|
||||
console.log("备忘录权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(EKEventStore);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Android权限查询
|
||||
function requestAndroidPermission(permissionID) {
|
||||
return new Promise((resolve, reject) => {
|
||||
plus.android.requestPermissions(
|
||||
[permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装
|
||||
function(resultObj) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < resultObj.granted.length; i++) {
|
||||
var grantedPermission = resultObj.granted[i];
|
||||
console.log('已获取的权限:' + grantedPermission);
|
||||
result = 1
|
||||
}
|
||||
for (var i = 0; i < resultObj.deniedPresent.length; i++) {
|
||||
var deniedPresentPermission = resultObj.deniedPresent[i];
|
||||
console.log('拒绝本次申请的权限:' + deniedPresentPermission);
|
||||
result = 0
|
||||
}
|
||||
for (var i = 0; i < resultObj.deniedAlways.length; i++) {
|
||||
var deniedAlwaysPermission = resultObj.deniedAlways[i];
|
||||
console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
|
||||
result = -1
|
||||
}
|
||||
resolve(result);
|
||||
// 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
|
||||
// if (result != 1) {
|
||||
// gotoAppPermissionSetting()
|
||||
// }
|
||||
},
|
||||
function(error) {
|
||||
console.log('申请权限错误:' + error.code + " = " + error.message);
|
||||
resolve({
|
||||
code: error.code,
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// 使用一个方法,根据参数判断权限
|
||||
function judgeIosPermission(permissionID) {
|
||||
if (permissionID == "location") {
|
||||
return judgeIosPermissionLocation()
|
||||
} else if (permissionID == "camera") {
|
||||
return judgeIosPermissionCamera()
|
||||
} else if (permissionID == "photoLibrary") {
|
||||
return judgeIosPermissionPhotoLibrary()
|
||||
} else if (permissionID == "record") {
|
||||
return judgeIosPermissionRecord()
|
||||
} else if (permissionID == "push") {
|
||||
return judgeIosPermissionPush()
|
||||
} else if (permissionID == "contact") {
|
||||
return judgeIosPermissionContact()
|
||||
} else if (permissionID == "calendar") {
|
||||
return judgeIosPermissionCalendar()
|
||||
} else if (permissionID == "memo") {
|
||||
return judgeIosPermissionMemo()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 跳转到**应用**的权限页面
|
||||
function gotoAppPermissionSetting() {
|
||||
if (isIos) {
|
||||
var UIApplication = plus.ios.import("UIApplication");
|
||||
var application2 = UIApplication.sharedApplication();
|
||||
var NSURL2 = plus.ios.import("NSURL");
|
||||
// var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");
|
||||
var setting2 = NSURL2.URLWithString("app-settings:");
|
||||
application2.openURL(setting2);
|
||||
|
||||
plus.ios.deleteObject(setting2);
|
||||
plus.ios.deleteObject(NSURL2);
|
||||
plus.ios.deleteObject(application2);
|
||||
} else {
|
||||
// console.log(plus.device.vendor);
|
||||
var Intent = plus.android.importClass("android.content.Intent");
|
||||
var Settings = plus.android.importClass("android.provider.Settings");
|
||||
var Uri = plus.android.importClass("android.net.Uri");
|
||||
var mainActivity = plus.android.runtimeMainActivity();
|
||||
var intent = new Intent();
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
|
||||
intent.setData(uri);
|
||||
mainActivity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查系统的设备服务是否开启
|
||||
// var checkSystemEnableLocation = async function () {
|
||||
function checkSystemEnableLocation() {
|
||||
if (isIos) {
|
||||
var result = false;
|
||||
var cllocationManger = plus.ios.import("CLLocationManager");
|
||||
var result = cllocationManger.locationServicesEnabled();
|
||||
console.log("系统定位开启:" + result);
|
||||
plus.ios.deleteObject(cllocationManger);
|
||||
return result;
|
||||
} else {
|
||||
var context = plus.android.importClass("android.content.Context");
|
||||
var locationManager = plus.android.importClass("android.location.LocationManager");
|
||||
var main = plus.android.runtimeMainActivity();
|
||||
var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
|
||||
var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
|
||||
console.log("系统定位开启:" + result);
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
judgeIosPermission: judgeIosPermission,
|
||||
requestAndroidPermission: requestAndroidPermission,
|
||||
checkSystemEnableLocation: checkSystemEnableLocation,
|
||||
gotoAppPermissionSetting: gotoAppPermissionSetting
|
||||
}
|
||||
+6
-3
@@ -2,8 +2,8 @@
|
||||
"name" : "瞬聊",
|
||||
"appid" : "__UNI__E41111F",
|
||||
"description" : "一款即时聊天软件",
|
||||
"versionName" : "3.4.6",
|
||||
"versionCode" : 346,
|
||||
"versionName" : "3.4.8",
|
||||
"versionCode" : 348,
|
||||
"transformPx" : false,
|
||||
"app-plus" : {
|
||||
"bounce" : "none",
|
||||
@@ -51,7 +51,10 @@
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>"
|
||||
"<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_MEDIA_IMAGES\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_MEDIA_VIDEO\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_MEDIA_VISUAL_USER_SELECTED\"/>"
|
||||
],
|
||||
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
|
||||
"minSdkVersion" : 21,
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"dependencies": {
|
||||
"@openim/client-sdk": "^0.0.11-ahpha.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"date-fns": "^2.30.0",
|
||||
@@ -14,4 +14,4 @@
|
||||
"worker-loader": "^3.0.8",
|
||||
"worker-plugin": "^5.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,14 +128,14 @@
|
||||
uni.request({
|
||||
url:url,
|
||||
success(res){
|
||||
//console.log(res.data);
|
||||
console.log(res.data);
|
||||
const result = res.data.result;
|
||||
_this.address = result.formatted_address;
|
||||
console.log( {
|
||||
lng: result.location.lon,
|
||||
lat: result.location.lat,
|
||||
address: result.formatted_address
|
||||
});
|
||||
// console.log( {
|
||||
// lng: result.location.lon,
|
||||
// lat: result.location.lat,
|
||||
// address: result.formatted_address
|
||||
// });
|
||||
//return 1;
|
||||
// 通过事件通道返回数据给父页面
|
||||
const eventChannel = _this.getOpenerEventChannel();
|
||||
@@ -143,7 +143,9 @@
|
||||
eventChannel.emit('onConfirm', {
|
||||
lng: result.location.lon,
|
||||
lat: result.location.lat,
|
||||
address: result.formatted_address
|
||||
name: result.addressComponent.town,
|
||||
address: result.formatted_address,
|
||||
addressComponent:result.addressComponent
|
||||
});
|
||||
uni.navigateBack();
|
||||
},
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
to="/pages/contact/applicationList/index?applicationType=NewGroup"
|
||||
thumb="/static/images/contact_new_group.png"></uni-list-item>
|
||||
<uni-list-item
|
||||
v-if="1==2"
|
||||
title="群聊"
|
||||
thumbSize="lg"
|
||||
to="/pages/contact/groupList/index"
|
||||
|
||||
@@ -67,7 +67,9 @@
|
||||
import SimpleEditor from "./SimpleEditor";
|
||||
import ChatingActionBar from "./ChatingActionBar";
|
||||
import Recoder from "./Recoder";
|
||||
|
||||
import {upload} from "@/api/login.js"
|
||||
import IM from "@/util/im.js";
|
||||
import permision from "@/js_sdk/wa-permission/permission.js"
|
||||
const needClearTypes = [MessageType.TextMessage];
|
||||
|
||||
const rtcChoose = [
|
||||
@@ -177,8 +179,12 @@
|
||||
if (needClearTypes.includes(message.contentType)) {
|
||||
this.$refs.customEditor.clear();
|
||||
}
|
||||
let method = IMMethods.SendMessage;
|
||||
if([MessageType.PictureMessage,MessageType.VoiceMessage,MessageType.VideoMessage,MessageType.FileMessage].includes(message.contentType)){
|
||||
method = IMMethods.SendMessageNotOss;
|
||||
}
|
||||
this.$emit("scrollToBottom");
|
||||
IMSDK.asyncApi(IMMethods.SendMessage, IMSDK.uuid(), {
|
||||
IMSDK.asyncApi(method, IMSDK.uuid(), {
|
||||
recvID: user_id,
|
||||
groupID: group_id,
|
||||
message,
|
||||
@@ -211,7 +217,6 @@
|
||||
});
|
||||
},
|
||||
recordAudioMsg(){
|
||||
|
||||
if (uni.getSystemInfoSync().platform == "android") {
|
||||
permission.requestAndroid("android.permission.RECORD_AUDIO"); //Android请求录音权限
|
||||
} else {
|
||||
@@ -281,36 +286,15 @@
|
||||
sendMediaMesage(paths) {
|
||||
const _this = this;
|
||||
paths.forEach(async (item) => {
|
||||
console.log(item);
|
||||
try {
|
||||
let message = null;
|
||||
if(item.search('.mp4')>0){
|
||||
const realVideoPath = await getPurePath(item);
|
||||
console.log('处理后的可用路径', realVideoPath);
|
||||
const info = await getVideoInfo(realVideoPath);
|
||||
//const cover = await getVideoCover(item);
|
||||
const res1 = await IMSDK.getVideoCover(item);
|
||||
//console.log(res1.path);
|
||||
const videoParams = {
|
||||
videoPath: realVideoPath,
|
||||
videoType: "mp4",
|
||||
duration: info.duration,
|
||||
snapshotPath: getPurePath(res1.path),
|
||||
//snapshotPath: getPurePath(cover),
|
||||
};
|
||||
console.log('videoParams', videoParams);
|
||||
message = await IMSDK.asyncApi(
|
||||
IMMethods.CreateVideoMessageFromFullPath,
|
||||
IMSDK.uuid(),
|
||||
videoParams
|
||||
);
|
||||
message = await IM.createVideoMessage(item);
|
||||
}else{
|
||||
message = await IMSDK.asyncApi(
|
||||
IMMethods.CreateImageMessageFromFullPath,
|
||||
IMSDK.uuid(),
|
||||
getPurePath(item)
|
||||
);
|
||||
message = await IM.createImageMessage(item);
|
||||
}
|
||||
//console.log(message);
|
||||
console.log(message);
|
||||
if(message){
|
||||
_this.sendMessage(message,_this.storeCurrentConversation.userID,_this.storeCurrentConversation.groupID);
|
||||
}
|
||||
@@ -401,6 +385,31 @@
|
||||
break;
|
||||
}
|
||||
},
|
||||
pickMedia(){
|
||||
const _this = this;
|
||||
plus.gallery.pick(({files})=>{
|
||||
console.log(files);
|
||||
_this.sendMediaMesage(files);
|
||||
}, (error )=>{
|
||||
console.log(error);
|
||||
}, {
|
||||
animation:true,
|
||||
confirmText:"确定",
|
||||
//crop:null,
|
||||
editable:true,
|
||||
filename:"_doc/",
|
||||
//filter:"none",//image,none,video
|
||||
filter:"image",
|
||||
maximum:9,
|
||||
multiple:true,
|
||||
permissionAlert:true,
|
||||
//popover:{},
|
||||
//selected:[""],
|
||||
onmaxed(){
|
||||
console.log("超出最大选择数");
|
||||
},
|
||||
});
|
||||
},
|
||||
onUserEvent(e){
|
||||
const _this = this;
|
||||
switch(e.type){
|
||||
@@ -455,33 +464,8 @@
|
||||
return ;
|
||||
}
|
||||
if(e.source == "album"){
|
||||
// IMSDK.pickFile().then(res=>{
|
||||
// console.log(res);
|
||||
// }).catch(e=>{
|
||||
// console.log(e);
|
||||
// });
|
||||
// return;
|
||||
plus.gallery.pick(({files})=>{
|
||||
_this.sendMediaMesage(files);
|
||||
}, (error )=>{
|
||||
console.log(error);
|
||||
}, {
|
||||
animation:true,
|
||||
confirmText:"确定",
|
||||
//crop:null,
|
||||
editable:true,
|
||||
filename:"_doc/",
|
||||
filter:"none",
|
||||
maximum:9,
|
||||
multiple:true,
|
||||
permissionAlert:true,
|
||||
//popover:{},
|
||||
//selected:[""],
|
||||
onmaxed(){
|
||||
console.log("超出最大选择数");
|
||||
},
|
||||
});
|
||||
}
|
||||
_this.pickMedia();
|
||||
}
|
||||
break;
|
||||
case "prepend_call_message":
|
||||
this.actionSheetMenu = [...rtcChoose];
|
||||
|
||||
@@ -49,7 +49,12 @@
|
||||
const imageWidth = this.message.pictureElem.sourcePicture.width;
|
||||
const aspectRatio = imageHeight / imageWidth;
|
||||
return 120 * aspectRatio;
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
src(newVal, oldVal) {
|
||||
console.log(newVal,oldVal);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
@@ -59,7 +64,12 @@
|
||||
const self = this;
|
||||
let url = "";
|
||||
// 如果有远程 snapshotUrl,则下载到 coverCachePath
|
||||
const snapshotUrl = (this.message.pictureElem.snapshotPicture?.url ?? this.message.pictureElem.sourcePath );
|
||||
//const snapshotUrl = (this.message.pictureElem.snapshotPicture?.url ?? this.message.pictureElem.sourcePath );
|
||||
const snapshotUrl = this.message.pictureElem.sourcePicture?.url;
|
||||
if(!snapshotUrl){
|
||||
console.log(this.message);
|
||||
return;
|
||||
}
|
||||
//console.log(snapshotUrl);
|
||||
util.cacheFile(snapshotUrl,`${this.conversationID}`).then((fn)=>{
|
||||
self.coverDownloading = false;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="video_message_container" @click="clickMediaItem">
|
||||
<view class="video_message_container">
|
||||
<u--image
|
||||
:showLoading="true"
|
||||
:src="src"
|
||||
:width="imgWidth"
|
||||
:height="maxHeight"
|
||||
mode="widthFix"
|
||||
@load="onLoaded"
|
||||
@click="clickMediaItem">
|
||||
@load="onLoaded" >
|
||||
<template v-slot:loading>
|
||||
<u-loading-icon color="red"></u-loading-icon>
|
||||
</template>
|
||||
@@ -21,8 +20,8 @@
|
||||
</view>
|
||||
<text class="progress-text">{{ videoDownloadProgress }}%</text>
|
||||
</view>
|
||||
<u-icon v-else-if="videoExists" class="play_icon" name="play-circle" size="48" color="#fff"></u-icon>
|
||||
<uni-icons v-else class="play_icon" type="cloud-download" size="48" color="#fff"></uni-icons>
|
||||
<u-icon v-else-if="videoExists" class="play_icon" name="play-circle" size="48" color="#ccc"></u-icon>
|
||||
<uni-icons v-else class="play_icon" type="cloud-download" size="48" color="#ccc"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 视频播放器组件 -->
|
||||
@@ -116,23 +115,17 @@
|
||||
},
|
||||
methods: {
|
||||
async init(){
|
||||
const self = this;
|
||||
const _this = this;
|
||||
console.log(this.message?.videoElem,this.conversationID);
|
||||
const snapshotUrl = this.message?.videoElem?.snapshotUrl;
|
||||
self.coverDownloading = true;
|
||||
_this.coverDownloading = true;
|
||||
//console.log(snapshotUrl);
|
||||
util.cacheFile(snapshotUrl,`${this.conversationID}`).then((fn)=>{
|
||||
self.coverDownloading = false;
|
||||
self.src = fn;
|
||||
_this.coverDownloading = false;
|
||||
_this.src = fn;
|
||||
//console.log(fn);
|
||||
});
|
||||
},
|
||||
clickMediaItem() {
|
||||
uni.previewImage({
|
||||
current: 0,
|
||||
urls: [this.message.videoElem?.snapshotUrl],
|
||||
indicator: "none",
|
||||
});
|
||||
_this.videoExists = util.fileExsit(util.getCachePath(_this.message?.videoElem?.videoUrl,`${_this.conversationID}`));
|
||||
},
|
||||
async onLoaded() {
|
||||
this.loadingWidth = "auto";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<view v-if="isNoticeMessage" class="notice_message_container" style="margin: 0 auto;" :id="`auchor${source.clientMsgID}`">
|
||||
<view v-if="isNoticeMessage" class="notice_message_container" :id="`auchor${source.clientMsgID}`">
|
||||
<text>{{ getNoticeContent }}</text>
|
||||
</view>
|
||||
<view v-else-if="source.contentType == 1519" class="notice_message_container" style="margin: 0 auto;" :id="`auchor${source.clientMsgID}`">
|
||||
<view v-else-if="source.contentType == 1519" class="notice_message_container" :id="`auchor${source.clientMsgID}`">
|
||||
<text @click="toAnnouncement">{{ announcementElem.opUser.nickname }}更新了群公告</text>
|
||||
</view>
|
||||
<view v-else class="message_wrapper">
|
||||
@@ -282,7 +282,7 @@
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
.message_content_wrap_shadow {
|
||||
box-shadow: 0px 0px 2px rgba(0,0,0,0.1);
|
||||
box-shadow: 0px 0px 0px rgba(0,0,0,0.1);
|
||||
}
|
||||
.message_content_wrap {
|
||||
@include vCenterBox();
|
||||
@@ -345,7 +345,7 @@
|
||||
// text-align: end;
|
||||
align-items: flex-end;
|
||||
.message_content_wrap_shadow {
|
||||
box-shadow: 0px 0px 2px #95e261;
|
||||
box-shadow: 0px 0px 0px #95e261;
|
||||
}
|
||||
.message_content_wrap {
|
||||
flex-direction: row-reverse;
|
||||
@@ -375,10 +375,14 @@
|
||||
.notice_message_container {
|
||||
@include ellipsisWithLine(2);
|
||||
text-align: center;
|
||||
margin: 24rpx 48rpx;
|
||||
padding: 24rpx 48rpx;
|
||||
word-break: break-word;
|
||||
// font-size: 24rpx;
|
||||
font-size: 0.85rem;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
:autoBack="true"
|
||||
>
|
||||
<view class="u-nav-slot" slot="right" v-if="isOwner || isAdmin">
|
||||
<u-button type="primary" size="mini" @click="save">保存</u-button>
|
||||
<u-button type="primary" @click="save">保存</u-button>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<u-parse v-if="!isOwner && !isAdmin" :content="announcement"></u-parse>
|
||||
@@ -16,7 +16,7 @@
|
||||
focus
|
||||
autoHeight
|
||||
height="500"
|
||||
maxlength="-1"
|
||||
maxlength="1500"
|
||||
border="none"
|
||||
:adjustPosition="false"
|
||||
class="textarea"
|
||||
@@ -77,4 +77,9 @@
|
||||
<style scoped lang="scss">
|
||||
.textarea{
|
||||
}
|
||||
.u-nav-slot{
|
||||
.u-button{
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -47,6 +47,7 @@
|
||||
</view>
|
||||
|
||||
<u-toast ref="uToast"></u-toast>
|
||||
<c-cut-avatar ref="cutAvatar" @save="saveAvatar" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -60,6 +61,7 @@
|
||||
import GroupMemberRow from "./components/GroupMemberRow.vue";
|
||||
import {getPurePath} from "@/util/common";
|
||||
import util from "@/util/index.js"
|
||||
import {upload} from "@/api/login.js";
|
||||
|
||||
const ConfirmTypes = {
|
||||
Dismiss: "Dismiss",
|
||||
@@ -273,6 +275,22 @@
|
||||
console.log(e);
|
||||
})
|
||||
},
|
||||
saveAvatar(e){
|
||||
if (!this.isAdmin && !this.isOwner) {
|
||||
return;
|
||||
}
|
||||
this.tempFilePath = e.path;
|
||||
upload(e.path,{
|
||||
'url':"/group/avatar",
|
||||
savePath: "groupavatar",
|
||||
groupID: this.storeCurrentConversation.groupID,
|
||||
}).then((res) => {
|
||||
console.log("上传成功",res);
|
||||
//userStore.selfInfo.faceURL = res.data.faceURL;
|
||||
}).catch((res1) => {
|
||||
console.log("上传失败",res1);
|
||||
});
|
||||
},
|
||||
updateGroupAvatar() {
|
||||
if (!this.isAdmin && !this.isOwner) {
|
||||
return;
|
||||
@@ -285,6 +303,8 @@
|
||||
tempFilePaths
|
||||
}) => {
|
||||
const path = tempFilePaths[0];
|
||||
this.$refs.cutAvatar.enterEditor(path);
|
||||
return ;
|
||||
const nameIdx = path.lastIndexOf("/") + 1;
|
||||
const typeIdx = path.lastIndexOf(".") + 1;
|
||||
const fileName = path.slice(nameIdx);
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
<template>
|
||||
<view class="content">
|
||||
<u-navbar title="选择背景图" :background="{ background: '#ffffff'}"
|
||||
:border-bottom="false">
|
||||
<view class="slot-wrap" slot="right">
|
||||
<uni-nav-bar
|
||||
left-icon="back"
|
||||
@clickLeft="uni.$u.route({type:'back'})"
|
||||
statusBar
|
||||
backgroundColor="#ffffff"
|
||||
:border="false"
|
||||
title="选择背景图">
|
||||
<template v-slot:footer>
|
||||
<u-button :custom-style="customBtnStyle" size="mini" :disabled="submitFlag"
|
||||
:type="submitFlag?'info ':'success'" @click="handleLink()">设置</u-button>
|
||||
</view>
|
||||
</u-navbar>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
<u-grid @click="clickGrid">
|
||||
<u-grid-item v-for="(item, index) in bgList" :key="index" :index="index" :custom-style="item.isCheck?girdItemCustomStyle:{}">
|
||||
<u-image :src="item.src" width="200rpx" height="200rpx" mode="aspectFill"></u-image>
|
||||
@@ -46,7 +51,10 @@ export default {
|
||||
handleLink(){
|
||||
const item = this.bgList.find(it=>it.isCheck);
|
||||
if(item){
|
||||
this.$u.vuex('circleBgImg', item.src);
|
||||
this.$store.commit('circle/SET_SETTINGS',{
|
||||
...this.$store.storeCircleSettings,
|
||||
bg:item.src
|
||||
});
|
||||
uni.navigateBack({
|
||||
delta:2
|
||||
})
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-cell-group>
|
||||
<u-cell-item title="选择内置背景图" :title-style="titleStyle"
|
||||
:border-bottom="false" :border-top="false"
|
||||
@click="linkToBuiltinBgImg"></u-cell-item>
|
||||
</u-cell-group>
|
||||
<u-gap :height="16" bg-color="#f4f4f5"></u-gap>
|
||||
<u-cell-group>
|
||||
<u-cell-item title="通过手机选择" :title-style="titleStyle"
|
||||
:border-bottom="false" :border-top="false"
|
||||
@click="chooseImg"></u-cell-item>
|
||||
</u-cell-group>
|
||||
|
||||
<u-toast ref="uToast" />
|
||||
<uni-nav-bar
|
||||
left-icon="back"
|
||||
@clickLeft="uni.$u.route({type:'back'})"
|
||||
statusBar
|
||||
backgroundColor="#ffffff"
|
||||
title="选择背景图">
|
||||
</uni-nav-bar>
|
||||
<uni-list>
|
||||
<uni-list-item disabled="true" title="选择内置背景图" @click="linkToBuiltinBgImg" clickable showArrow></uni-list-item>
|
||||
<uni-list-item title="通过手机选择" @click="chooseImg" clickable showArrow></uni-list-item>
|
||||
</uni-list>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {upload} from "@/api/login"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -46,26 +45,21 @@ export default {
|
||||
|
||||
//上传返回图片
|
||||
myUpload(filePath) {
|
||||
let that=this;
|
||||
let _this=this;
|
||||
let obj = {
|
||||
filePath:filePath,
|
||||
savePath: "friendCircle" //文件存放目录
|
||||
'url':"/friendcircle/upload_bg",
|
||||
savePath: "circle" //文件存放目录
|
||||
}
|
||||
console.log("通过手机选择",obj);
|
||||
this.globalUtil.globalUpload(that,{
|
||||
param:obj,
|
||||
success: (res1) => {
|
||||
console.log("上传成功",res1);
|
||||
let avatar= res1.result.url;
|
||||
that.$u.vuex('circleBgImg',avatar);
|
||||
uni.navigateBack();
|
||||
},
|
||||
fail:(res1) => {
|
||||
console.log("上传失败",res1);
|
||||
},
|
||||
complete: (res1) => {
|
||||
console.log("上传完成",res1);
|
||||
}
|
||||
upload(filePath,obj).then((res1) => {
|
||||
_this.$store.commit('circle/SET_SETTINGS',{
|
||||
..._this.$store.storeCircleSettings,
|
||||
bg:res1.data.url
|
||||
});
|
||||
uni.navigateBack();
|
||||
}).catch((res1) => {
|
||||
console.log("上传失败",res1);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -39,14 +39,9 @@
|
||||
|
||||
|
||||
<!-- 视频 -->
|
||||
<view class="u-m-b-30 u-m-t-30 u-flex u-row-left u-col-center"
|
||||
<view class="u-m-b-30 u-m-t-30 u-flex u-row-left u-col-center"
|
||||
v-if="item.files.length > 0&&item.releaseType==2" @tap="previewImg(0, item)">
|
||||
<view v-if="vuex_OSPlat=='ios'">
|
||||
<u-image width="280rpx" :src="getVideoPoster(item.files[0])" mode="widthFix">
|
||||
<u-loading-icon slot="loading"></u-loading-icon>
|
||||
</u-image>
|
||||
</view>
|
||||
<view v-else class="u-flex u-row-center u-col-center"
|
||||
<view class="u-flex u-row-center u-col-center"
|
||||
style="border: 1rpx solid #36648b;width:280rpx;height:120rpx;border-radius: 16rpx;">
|
||||
<u-icon name="play-circle" size="48" color="#36648b"
|
||||
label="点击查看视频" label-pos="bottom"></u-icon>
|
||||
@@ -55,9 +50,9 @@
|
||||
</view>
|
||||
|
||||
<!-- 地点 -->
|
||||
<view v-if="(item.address&&item.address.chooseFlag)==true" class="u-line-2 u-m-t-10 u-m-b-10" style="font-size: 30rpx;color: #36648b;">
|
||||
<u-icon name="map" color="#36648b" size="30" :custom-style="{marginLeft:'-4rpx'}"></u-icon>
|
||||
<text> {{ item.address.name}}</text>
|
||||
<view v-if="(item.address&&item.address.chooseFlag)==true" @click="gotomap(item)" class="content-address">
|
||||
<u-icon name="map" color="#36648b"></u-icon>
|
||||
<u-text class="name" :lines="1" :text="item.address.name"></u-text>
|
||||
</view>
|
||||
|
||||
<!-- 相对时间 点赞按钮等 -->
|
||||
@@ -182,6 +177,12 @@
|
||||
return "http://192.168.31.125:9090/we-chat/images/friendCircle/1715421601709.mp4";
|
||||
//return videoSrc;
|
||||
},
|
||||
gotomap(item){
|
||||
const addr = item.address;
|
||||
uni.navigateTo({
|
||||
url:`/pages/common/map?type=viewlocation&lng=${addr.longitude}&lat=${addr.latitude}&address=${addr.address}`
|
||||
})
|
||||
},
|
||||
cdn:util.cdn
|
||||
}
|
||||
}
|
||||
@@ -254,7 +255,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-address{
|
||||
font-size: 26rpx;
|
||||
color: #36648b;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 10rpx;
|
||||
.u-icon{
|
||||
|
||||
}
|
||||
.name{
|
||||
}
|
||||
}
|
||||
.msg-box {
|
||||
width: 100%;
|
||||
background-color: #FFF;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</u-navbar>
|
||||
<!-- 我的朋友圈基本信息 -->
|
||||
<view class="content-imgbox" :class="{top:scrollTop>bannarHeight}">
|
||||
<image class="bgimg" v-if="storeCircleSettings.bg" :src="storeCircleSettings.bg" mode="scaleToFill" @tap="showSheet"></image>
|
||||
<image class="bgimg" v-if="storeCircleSettings.bg" :src="cdn(storeCircleSettings.bg)" mode="scaleToFill" @tap="showSheet"></image>
|
||||
<view class="bgimg" v-else @tap="showSheet"></view>
|
||||
|
||||
<MyAvatar class="headimg" :src="storeSelfInfo.faceURL" :desc="storeSelfInfo.nickname || storeSelfInfo.remark"
|
||||
@@ -90,9 +90,9 @@
|
||||
import {getFriendCircle} from "@/api/login.js"
|
||||
import UserBase from "@/components/User.vue"
|
||||
import MyAvatar from "@/components/MyAvatar/index.vue";
|
||||
import util from "@/util/index.js";
|
||||
import CircleItem from "./components/circleItem.vue"
|
||||
import { mapGetters } from "vuex";
|
||||
import util from "@/util";
|
||||
export default {
|
||||
name: 'firendCircle',
|
||||
mixins:[UserBase],
|
||||
@@ -185,6 +185,7 @@
|
||||
|
||||
methods: {
|
||||
goto:util.goto,
|
||||
cdn:util.cdn,
|
||||
clearUnReadCount(){
|
||||
this.$store.dispatch('circle/updateUnreadCount',0-this.unreadCount);
|
||||
},
|
||||
@@ -244,11 +245,13 @@
|
||||
showTypeSheet() {
|
||||
const _this = this;
|
||||
uni.showActionSheet({
|
||||
itemList:['选择照片','选择视频'],
|
||||
itemList:['文字','照片'/*,'视频'*/],
|
||||
success: function (res) {
|
||||
//toChooseRelease
|
||||
if(res.tapIndex<2){
|
||||
if([1,2].includes(res.tapIndex)){
|
||||
_this.toChooseRelease(res.tapIndex);
|
||||
}else{
|
||||
_this.linkToRelease({releaseType:0})
|
||||
}
|
||||
},
|
||||
fail: function (res) {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
:adjust-position="true" :auto-blur="true" @linechange="inputLineChange" @input="inputing"
|
||||
:confirm-hold="true" :show-confirm-bar="false"
|
||||
:focus="inputFocusFlag" :disable-default-padding="true"
|
||||
v-model="content" :cursor="content.length" :maxlength="-1" />
|
||||
v-model="content" :cursor="content.length" :maxlength="1500" />
|
||||
</scroll-view>
|
||||
<!-- 文件选择区 -->
|
||||
<view v-if="releaseType!=0" class="uploadBox">
|
||||
@@ -49,29 +49,33 @@
|
||||
</view>
|
||||
<!-- 选项 -->
|
||||
<view class="tips">
|
||||
<u-cell-group>
|
||||
<!-- :value="address.name" :value-style="customValueStyle" :label="address.address" -->
|
||||
<u-cell bg-color="#ffffff"
|
||||
:title="address.chooseFlag?(address.name):'所在位置'" :title-style="customTitleStyle"
|
||||
:value="address.chooseFlag?(address.address):'请选择'" isLink
|
||||
@click="toChooseLocation()">
|
||||
<view slot="icon" class="u-flex u-row-center u-col-center">
|
||||
<u-icon name="map" size="32" :color="address.chooseFlag?'#19be6b':'#606266'"></u-icon>
|
||||
</view>
|
||||
</u-cell>
|
||||
<u-cell bg-color="#ffffff" title="提醒谁看" :title-style="customTitleStyle" @click="toRemind">
|
||||
<view slot="icon" class="u-flex u-row-center u-col-center">
|
||||
<u-icon name="/static/images/friendCircle/at.png" width="24" height="24" color="#606266"></u-icon>
|
||||
</view>
|
||||
</u-cell>
|
||||
<u-cell bg-color="#ffffff" @click="toSetPromission()"
|
||||
title="谁可以看" :title-style="customTitleStyle"
|
||||
:value="'公开'" :value-style="customValueStyle">
|
||||
<view slot="icon" class="u-flex u-row-center u-col-center">
|
||||
<u-icon name="account" size="32" color="#606266"></u-icon>
|
||||
</view>
|
||||
</u-cell>
|
||||
</u-cell-group>
|
||||
<uni-list>
|
||||
<uni-list-item
|
||||
title="所在位置"
|
||||
:rightText="address.chooseFlag?(address.name):'请选择'"
|
||||
:show-extra-icon="true"
|
||||
:extra-icon="{color: '#666',size: '22',type: 'location-filled'}"
|
||||
clickable
|
||||
showArrow
|
||||
@click="toChooseLocation">
|
||||
</uni-list-item>
|
||||
<uni-list-item v-if="1==2"
|
||||
title="提醒谁看"
|
||||
:rightText="address.chooseFlag?(address.address):'请选择'"
|
||||
clickable
|
||||
showArrow
|
||||
@click="toRemind">
|
||||
</uni-list-item>
|
||||
<uni-list-item
|
||||
title="谁可以看"
|
||||
rightText="公开"
|
||||
:show-extra-icon="true"
|
||||
:extra-icon="{color: '#666',size: '22',type: 'notification-filled'}"
|
||||
clickable
|
||||
showArrow
|
||||
@click="toSetPromission">
|
||||
</uni-list-item>
|
||||
</uni-list>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -273,21 +277,23 @@
|
||||
//去选择所在位置
|
||||
toChooseLocation:function(){
|
||||
let that=this;
|
||||
uni.chooseLocation({
|
||||
success: function (res) {
|
||||
// console.log('位置名称:' + res.name);
|
||||
// console.log('详细地址:' + res.address);
|
||||
// console.log('纬度:' + res.latitude);
|
||||
//console.log('经度:' + res.longitude);
|
||||
that.address=res;
|
||||
that.address.chooseFlag=true;
|
||||
//console.log("that.address",that.address);
|
||||
},
|
||||
fail:function(){
|
||||
that.address={};
|
||||
that.address.chooseFlag=false;
|
||||
uni.navigateTo({
|
||||
url:"/pages/common/map",
|
||||
events:{
|
||||
onConfirm(res) {
|
||||
//_this.sendLocationMessage(res);
|
||||
that.address={
|
||||
address:res.address,
|
||||
name:`${res.addressComponent.city}•${res.addressComponent.town}`,
|
||||
latitude:res.lat,
|
||||
longitude:res.lng,
|
||||
};
|
||||
that.address.chooseFlag=true;
|
||||
console.log(res);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
return ;
|
||||
},
|
||||
//设置发布朋友圈的查看权限
|
||||
toSetPromission:function(){
|
||||
@@ -422,28 +428,16 @@
|
||||
let that=this;
|
||||
console.error('submitPublish');
|
||||
uni.$u.http.post('/friendcircle/create',param).then(res => {
|
||||
let newCircle=res;
|
||||
if(newCircle.address!=null&&newCircle.address.length>0){
|
||||
newCircle.address=JSON.parse(newCircle.address);
|
||||
}else{
|
||||
newCircle.address={"chooseFlag":false};
|
||||
}
|
||||
if(newCircle.fileList!=null&&newCircle.fileList.length>0){
|
||||
newCircle.fileList=JSON.parse(newCircle.fileList);
|
||||
}else{
|
||||
newCircle.fileList=[];
|
||||
}
|
||||
if(newCircle.praise!=null){
|
||||
newCircle.praise=JSON.parse(newCircle.praise);
|
||||
}else{
|
||||
newCircle.praise=[];
|
||||
}
|
||||
if(newCircle.comment!=null){
|
||||
newCircle.comment=JSON.parse(newCircle.comment);
|
||||
}
|
||||
else{
|
||||
newCircle.comment=[];
|
||||
}
|
||||
console.log("发布成功",res);
|
||||
let newCircle=res.data;
|
||||
newCircle['user'] = {
|
||||
"id": this.$store.getters.storeSelfInfo.userID,
|
||||
"nickname": this.$store.getters.storeSelfInfo.nickname,
|
||||
"avatar": this.$store.getters.storeSelfInfo.faceURL,
|
||||
};
|
||||
newCircle['likes'] = [];
|
||||
newCircle['comments'] = [];
|
||||
newCircle['is_liked'] = false;
|
||||
let circleDataList=[...this.circleData];
|
||||
circleDataList.unshift(newCircle);
|
||||
that.$store.commit('circle/SET_LIST',circleDataList);
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
|
||||
<u-datetime-picker :minDate="0" :maxDate="nowDate" :show="showDatePicker" @confirm="confirmDate"
|
||||
@cancel="() => (showDatePicker = false)" v-model="selfInfo.birth" mode="date" />
|
||||
|
||||
<c-cut-avatar ref="cutAvatar" @save="saveAvatar" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
businessInfoUpdate
|
||||
} from "@/api/login";
|
||||
import {businessInfoUpdate,upload} from "@/api/login";
|
||||
import IMSDK from "openim-uniapp-polyfill";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import MyAvatar from "@/components/MyAvatar/index.vue";
|
||||
@@ -87,14 +87,31 @@
|
||||
},
|
||||
});
|
||||
},
|
||||
saveAvatar(e){
|
||||
this.tempFilePath = e.path;
|
||||
upload(e.path,{
|
||||
'url':"/user/avatar",
|
||||
savePath: "avatar"
|
||||
}).then((res) => {
|
||||
console.log("上传成功",res);
|
||||
this.$store.commit("user/SET_SELF_INFO",{
|
||||
...this.$store.getters.storeSelfInfo,
|
||||
faceURL: res.data.avatar,
|
||||
});
|
||||
}).catch((res1) => {
|
||||
console.log("上传失败",res1);
|
||||
});
|
||||
},
|
||||
updateAvatar() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ["compressed"],
|
||||
sizeType: ["original"],
|
||||
success: async ({
|
||||
tempFilePaths
|
||||
}) => {
|
||||
const path = tempFilePaths[0];
|
||||
this.$refs.cutAvatar.enterEditor(path);
|
||||
return ;
|
||||
const nameIdx = path.lastIndexOf("/") + 1;
|
||||
const typeIdx = path.lastIndexOf(".") + 1;
|
||||
const fileName = path.slice(nameIdx);
|
||||
|
||||
@@ -31,6 +31,7 @@ const actions = {
|
||||
},
|
||||
async getFriendCircleInfo({ commit, state}) {
|
||||
uni.$u.http.get('/friendcircle/info').then(data=>{
|
||||
console.log("获取朋友圈信息",data);
|
||||
commit("SET_UNREAD_COUNT", data.unread_count);
|
||||
commit("SET_TOP_UNREAD_ITEMS", data.top_unread_items);
|
||||
commit("SET_SETTINGS", data.settings);
|
||||
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
|
||||
import IMSDK,{IMMethods} from "openim-uniapp-polyfill";
|
||||
import {offlinePushInfo} from "@/util/imCommon";
|
||||
import {upload} from "@/api/login.js";
|
||||
import {getVideoInfo} from "@/util/common";
|
||||
// #ifdef APP
|
||||
import {downloadFile} from "@/uni_modules/network-manage";
|
||||
// #endif
|
||||
export const imapi = (method,data)=>{
|
||||
return new Promise((resolve, reject) => {
|
||||
IMSDK.asyncApi(method,IMSDK.uuid(),data)
|
||||
.then(res=>{
|
||||
return resolve(res);
|
||||
})
|
||||
.catch(e=>{
|
||||
return reject(e);
|
||||
})
|
||||
});
|
||||
};
|
||||
export const copyFileToTempPath = (src) => {
|
||||
//plus.io.PRIVATE_DOC;
|
||||
console.log('src', src);
|
||||
console.log('src', src.includes(plus.io.PRIVATE_DOC));
|
||||
return new Promise((resolve, reject) => {
|
||||
plus.io.resolveLocalFileSystemURL(src, (entry) => {
|
||||
const cacheFilePath = '_doc/uniapp_temp/'+entry.name;
|
||||
console.log('cacheFilePath', cacheFilePath);
|
||||
const task = downloadFile({
|
||||
url:src,
|
||||
timeout: 30000,
|
||||
filePath:cacheFilePath,
|
||||
success(res) {
|
||||
console.log('res',res);
|
||||
},
|
||||
fail(e){
|
||||
console.log('e',e);
|
||||
},
|
||||
complate(){
|
||||
task = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
return ;
|
||||
|
||||
plus.io.resolveLocalFileSystemURL(src, (entry) => {
|
||||
console.log('entry name', entry.name);
|
||||
console.log('dir', '_doc/uniapp_temp/');
|
||||
entry.copyTo(plus.io.PUBLIC_DOCUMENTS, '/uniapp_temp/'+entry.name, (newEntry) => {
|
||||
console.log('newEntry', newEntry.fullPath);
|
||||
resolve(newEntry.toLocalURL());
|
||||
}, reject);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
export const getPurePath = (path)=>{
|
||||
if(!path)return "";
|
||||
const prefix = "file://";
|
||||
const relativeRrefix = "_doc/";
|
||||
if (path.includes(prefix)) {
|
||||
path = path.replace(prefix, "");
|
||||
}
|
||||
if (path.includes(relativeRrefix)) {
|
||||
path = plus.io.convertLocalFileSystemURL(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
export const createVoiceMessage = async (path)=>{
|
||||
};
|
||||
export const createFileMessage = async (path)=>{
|
||||
};
|
||||
export const getVideoCover = async (path)=>{
|
||||
return new Promise((resolve, reject) => {
|
||||
IMSDK.getVideoCover(path)
|
||||
.then(res=>{
|
||||
console.log('res', res);
|
||||
return resolve(res);
|
||||
})
|
||||
.catch(e=>{
|
||||
console.log('e', e);
|
||||
return reject(e);
|
||||
})
|
||||
});
|
||||
};
|
||||
export const createVideoMessage = (path)=>{
|
||||
return new Promise(async(resolve, reject) => {
|
||||
console.log('处理前的可用路径', path);
|
||||
//const realVideoPath = await copyFileToTempPath(path);
|
||||
const realVideoPath = await getPurePath(path);
|
||||
//console.log('处理后的可用路径', realVideoPath);
|
||||
const info = await getVideoInfo(realVideoPath);
|
||||
console.log('info', info);
|
||||
const cover = await getVideoCover(realVideoPath);
|
||||
console.log('cover', cover);
|
||||
const coverresult = await upload(cover,{savePath: "msg"});
|
||||
console.log('coverresult', coverresult);
|
||||
if(coverresult.code !=0){
|
||||
uni.$u.toast(coverresult.msg);
|
||||
return reject(coverresult.msg);
|
||||
}
|
||||
const videoresult = await upload(realVideoPath,{savePath: "msg"},(res)=>{
|
||||
uni.showLoading({
|
||||
title: res.progress+"%",
|
||||
})
|
||||
});
|
||||
console.log('videoresult', videoresult);
|
||||
const video_url = "";
|
||||
//封面
|
||||
const cover_url = `${video_url}?x-oss-process=video/snapshot,t_7000,f_jpg,w_800,h_600,m_fast`;
|
||||
uni.hideLoading();
|
||||
|
||||
if(videoresult.code !=0){
|
||||
uni.$u.toast(videoresult.msg);
|
||||
return reject(videoresult.msg);
|
||||
}
|
||||
imapi(IMMethods.CreateVideoMessageByURL,{
|
||||
videoPath: realVideoPath,
|
||||
duration: info.duration,
|
||||
videoType: info.type.split("/")[1],
|
||||
snapshotPath: cover,
|
||||
videoUUID: IMSDK.uuid(),
|
||||
videoUrl: videoresult.data[0].file_url,
|
||||
videoSize: videoresult.data[0].size,
|
||||
snapshotUUID: IMSDK.uuid(),
|
||||
snapshotSize: coverresult.data[0].size,
|
||||
snapshotUrl: coverresult.data[0].file_url,
|
||||
snapshotWidth: coverresult.data[0].file_width,
|
||||
snapshotHeight: coverresult.data[0].file_height,
|
||||
snapShotType: coverresult.data[0].extension,
|
||||
}).then(res=>{
|
||||
console.log('res', res);
|
||||
resolve(res);
|
||||
}).catch(err=>{
|
||||
console.log('err', err);
|
||||
reject(err);
|
||||
})
|
||||
return ;
|
||||
//const realVideoPath = await getPurePath(path);
|
||||
//console.log('处理后的可用路径', realVideoPath);
|
||||
//const info = await getVideoInfo(realVideoPath);
|
||||
//const cover = await getVideoCover(path);
|
||||
//const res1 = await IMSDK.getVideoCover(path);
|
||||
//console.log(res1.path);
|
||||
const videoParams = {
|
||||
videoPath: realVideoPath,
|
||||
videoType: "mp4",
|
||||
duration: info.duration,
|
||||
snapshotPath: getPurePath(res1.path),
|
||||
//snapshotPath: getPurePath(cover),
|
||||
};
|
||||
console.log('videoParams', videoParams);
|
||||
message = await IMSDK.asyncApi(
|
||||
IMMethods.CreateVideoMessageFromFullPath,
|
||||
IMSDK.uuid(),
|
||||
videoParams
|
||||
);
|
||||
});
|
||||
};
|
||||
export const createImageMessage = async (path)=>{
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const result = await upload(path,{savePath: "msg"});
|
||||
if(result.code !=0){
|
||||
uni.$u.toast(result.msg);
|
||||
return ;
|
||||
}
|
||||
const picBaseInfo = {
|
||||
uuid: IMSDK.uuid(),
|
||||
type: result.data[0].extension,
|
||||
size: result.data[0].size,
|
||||
width: result.data[0].file_width,
|
||||
height: result.data[0].file_height,
|
||||
url: result.data[0].file_url
|
||||
};
|
||||
|
||||
const message = await IMSDK.asyncApi(IMMethods.CreateImageMessageByURL,IMSDK.uuid(),{
|
||||
sourcePicture: picBaseInfo,
|
||||
bigPicture: picBaseInfo,
|
||||
snapshotPicture: picBaseInfo,
|
||||
sourcePath: result.data[0].file_url
|
||||
});
|
||||
console.log('message', message);
|
||||
return resolve(message);
|
||||
const tempPath = await copyFileToTempPath(path);
|
||||
console.log(tempPath);
|
||||
imapi(IMMethods.CreateImageMessageFromFullPath,getPurePath(tempPath)).then(res=>{
|
||||
console.log(res);
|
||||
resolve(res);
|
||||
}).catch(err=>{
|
||||
console.log(err);
|
||||
reject(err);
|
||||
})
|
||||
});
|
||||
}
|
||||
export const sendMessage = (message, user_id, group_id) => {
|
||||
let method = IMMethods.SendMessage;
|
||||
if([MessageType.PictureMessage,MessageType.VoiceMessage,MessageType.VideoMessage,MessageType.FileMessage].includes(message.contentType)){
|
||||
method = IMMethods.SendMessageNotOss;
|
||||
}
|
||||
return imapi(method,{recvID: user_id,groupID: group_id,message,offlinePushInfo,});
|
||||
};
|
||||
export default {
|
||||
imapi,
|
||||
sendMessage,
|
||||
createVoiceMessage,
|
||||
createVideoMessage,
|
||||
createFileMessage,
|
||||
createImageMessage,
|
||||
getPurePath,
|
||||
copyFileToTempPath,
|
||||
}
|
||||
@@ -245,6 +245,23 @@ const get_absolute_path = (fn)=>{
|
||||
return plus.io.convertLocalFileSystemURL(fn);
|
||||
}
|
||||
const pendingDownloads = new Map();
|
||||
const getCachePath = (url,saveDir)=>{
|
||||
if(!url || !url.startsWith('http')){
|
||||
return url;
|
||||
}
|
||||
const key = md5(url);
|
||||
var ext = "png"
|
||||
if(url.toLowerCase().indexOf('.mp4')!==-1){
|
||||
ext = "mp4";
|
||||
}
|
||||
let cacheDir = plus.io.convertLocalFileSystemURL(`_doc/{{dir}}/{{key}}.{{ext}}`);
|
||||
if(uni.getSystemInfoSync().osName == 'android'){
|
||||
cacheDir = cacheDir.replace('apps/'+plus.runtime.appid+'/doc','cache');
|
||||
}
|
||||
return cacheDir.replace('{{dir}}',saveDir)
|
||||
.replace('{{key}}',key)
|
||||
.replace('{{ext}}',ext);
|
||||
}
|
||||
const cacheFile = (url, saveDir,progressCallback) => {
|
||||
//console.log(url);
|
||||
// #ifndef APP
|
||||
@@ -462,6 +479,7 @@ export default{
|
||||
toMapAPP,
|
||||
cacheFile,
|
||||
fileExsit,
|
||||
getCachePath,
|
||||
get_absolute_path,
|
||||
// #ifdef APP
|
||||
downloadFile,
|
||||
|
||||
@@ -19,6 +19,13 @@ module.exports = (vm) => {
|
||||
...config.header,
|
||||
token:uni.getStorageSync("BusinessToken"),
|
||||
operationID: uuidV4(),
|
||||
client:uni.getSystemInfoSync().osName,
|
||||
// #ifdef APP-PLUS
|
||||
ClientVersion:plus.runtime.versionCode,
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
ClientVersion:350,
|
||||
// #endif
|
||||
};
|
||||
if(typeof config.data === 'object'){
|
||||
config.data = JSON.stringify(config.data);
|
||||
|
||||
Reference in New Issue
Block a user