Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui
|
@ -3,8 +3,8 @@ var BASE = {
|
||||||
* @description api请求基础路径
|
* @description api请求基础路径
|
||||||
*/
|
*/
|
||||||
API_DEV: {
|
API_DEV: {
|
||||||
common: "https://common-api.pickmall.cn",
|
common: "http://192.168.0.113:8890",
|
||||||
buyer: "https://buyer-api.pickmall.cn",
|
buyer: "http://192.168.0.113:8898",
|
||||||
seller: "https://store-api.pickmall.cn",
|
seller: "https://store-api.pickmall.cn",
|
||||||
manager: "https://admin-api.pickmall.cn"
|
manager: "https://admin-api.pickmall.cn"
|
||||||
// common: "http://192.168.0.105:8890",
|
// common: "http://192.168.0.105:8890",
|
||||||
|
|
|
@ -212,3 +212,52 @@ export function receiptSelect (params) {
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取全部配送方式
|
||||||
|
*/
|
||||||
|
export function shippingMethodList(params) {
|
||||||
|
return request({
|
||||||
|
url: `/buyer/trade/carts/shippingMethodList`,
|
||||||
|
method: Method.GET,
|
||||||
|
needToken: true,
|
||||||
|
params: params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取全部配送方式
|
||||||
|
*/
|
||||||
|
export function storeAddressList(params) {
|
||||||
|
return request({
|
||||||
|
url: `/buyer/store/address/shippingMethodList`,
|
||||||
|
method: Method.GET,
|
||||||
|
needToken: true,
|
||||||
|
params: params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置自提地址ID
|
||||||
|
* @param addressId
|
||||||
|
*/
|
||||||
|
export function setStoreAddressId(storeAddressId,way) {
|
||||||
|
return request({
|
||||||
|
url: `/buyer/trade/carts/storeAddress?storeAddressId=${storeAddressId}&way=${way}`,
|
||||||
|
method: Method.GET,
|
||||||
|
needToken: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交配送方式
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export function setShipMethod(params) {
|
||||||
|
return request({
|
||||||
|
url: "/buyer/trade/carts/shippingMethod",
|
||||||
|
method: Method.PUT,
|
||||||
|
needToken: true,
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -75,3 +75,15 @@ export function applyStatus () {
|
||||||
method: Method.GET
|
method: Method.GET
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取自提点信息
|
||||||
|
* @param storeId
|
||||||
|
*/
|
||||||
|
export function getStoreAddress(storeId,params) {
|
||||||
|
return request({
|
||||||
|
url: `/buyer/store/address/page/${storeId}`,
|
||||||
|
method: Method.GET,
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -8,26 +8,18 @@
|
||||||
<div class="shop-nav-container">
|
<div class="shop-nav-container">
|
||||||
<Breadcrumb>
|
<Breadcrumb>
|
||||||
<BreadcrumbItem to="/">首页</BreadcrumbItem>
|
<BreadcrumbItem to="/">首页</BreadcrumbItem>
|
||||||
<BreadcrumbItem
|
<BreadcrumbItem v-for="(item, index) in categoryBar" :to="goGoodsList(index)" target="_blank" :key="index">
|
||||||
v-for="(item, index) in categoryBar"
|
|
||||||
:to="goGoodsList(index)"
|
|
||||||
target="_blank"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
</Breadcrumb>
|
</Breadcrumb>
|
||||||
<div class="store-collect">
|
<div class="store-collect">
|
||||||
<span class="mr_10" v-if="goodsMsg.data">
|
<span class="mr_10" v-if="goodsMsg.data">
|
||||||
<router-link :to="'Merchant?id=' + goodsMsg.data.storeId">{{
|
<router-link :to="'Merchant?id=' + goodsMsg.data.storeId">{{
|
||||||
goodsMsg.data.storeName
|
goodsMsg.data.storeName
|
||||||
}}</router-link>
|
}}</router-link>
|
||||||
</span>
|
</span>
|
||||||
<span @click="collect">
|
<span @click="collect">
|
||||||
<Icon
|
<Icon type="ios-heart" :color="storeCollected ? '#ed3f14' : '#666'" />
|
||||||
type="ios-heart"
|
|
||||||
:color="storeCollected ? '#ed3f14' : '#666'"
|
|
||||||
/>
|
|
||||||
{{ storeCollected ? "已收藏店铺" : "收藏店铺" }}
|
{{ storeCollected ? "已收藏店铺" : "收藏店铺" }}
|
||||||
</span>
|
</span>
|
||||||
<span class="ml_10" @click="IMService()">联系客服</span>
|
<span class="ml_10" @click="IMService()">联系客服</span>
|
||||||
|
@ -36,11 +28,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 商品信息展示 -->
|
<!-- 商品信息展示 -->
|
||||||
<ShowGoods
|
<ShowGoods @handleClickSku="targetClickSku" v-if="goodsMsg.data" :detail="goodsMsg"></ShowGoods>
|
||||||
@handleClickSku="targetClickSku"
|
|
||||||
v-if="goodsMsg.data"
|
|
||||||
:detail="goodsMsg"
|
|
||||||
></ShowGoods>
|
|
||||||
<!-- 商品详细展示 -->
|
<!-- 商品详细展示 -->
|
||||||
<ShowGoodsDetail v-if="goodsMsg.data" :detail="goodsMsg"></ShowGoodsDetail>
|
<ShowGoodsDetail v-if="goodsMsg.data" :detail="goodsMsg"></ShowGoodsDetail>
|
||||||
|
|
||||||
|
@ -66,14 +54,14 @@ import { getIMDetail } from "@/api/common";
|
||||||
import Storage from "../plugins/storage";
|
import Storage from "../plugins/storage";
|
||||||
export default {
|
export default {
|
||||||
name: "GoodsDetail",
|
name: "GoodsDetail",
|
||||||
beforeRouteEnter(to, from, next) {
|
beforeRouteEnter (to, from, next) {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
next();
|
next();
|
||||||
},
|
},
|
||||||
created() {
|
created () {
|
||||||
this.getGoodsDetail();
|
this.getGoodsDetail();
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
goodsMsg: {}, // 商品信息
|
goodsMsg: {}, // 商品信息
|
||||||
isLoading: false, // 加载状态
|
isLoading: false, // 加载状态
|
||||||
|
@ -85,7 +73,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 跳转im客服
|
// 跳转im客服
|
||||||
async IMService() {
|
async IMService () {
|
||||||
// 获取访问Token
|
// 获取访问Token
|
||||||
let accessToken = Storage.getItem("accessToken");
|
let accessToken = Storage.getItem("accessToken");
|
||||||
await this.getIMDetailMethods();
|
await this.getIMDetailMethods();
|
||||||
|
@ -95,25 +83,29 @@ export default {
|
||||||
}
|
}
|
||||||
window.open(
|
window.open(
|
||||||
this.IMLink +
|
this.IMLink +
|
||||||
"?token=" +
|
"?token=" +
|
||||||
accessToken +
|
accessToken +
|
||||||
"&id=" +
|
"&id=" +
|
||||||
this.goodsMsg.data.storeId
|
this.goodsMsg.data.storeId +
|
||||||
|
"&goodsId=" +
|
||||||
|
this.goodsMsg.data.goodsId +
|
||||||
|
"&skuId=" +
|
||||||
|
this.goodsMsg.data.id
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
// 获取im信息
|
// 获取im信息
|
||||||
async getIMDetailMethods() {
|
async getIMDetailMethods () {
|
||||||
let res = await getIMDetail();
|
let res = await getIMDetail();
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.IMLink = res.result;
|
this.IMLink = res.result;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 点击规格
|
// 点击规格
|
||||||
targetClickSku(val) {
|
targetClickSku (val) {
|
||||||
this.getGoodsDetail(val);
|
this.getGoodsDetail(val);
|
||||||
},
|
},
|
||||||
// 获取商品详情
|
// 获取商品详情
|
||||||
getGoodsDetail(val) {
|
getGoodsDetail (val) {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
const params = val || this.$route.query;
|
const params = val || this.$route.query;
|
||||||
|
|
||||||
|
@ -179,7 +171,7 @@ export default {
|
||||||
this.$router.push("/");
|
this.$router.push("/");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
goGoodsList(currIndex) {
|
goGoodsList (currIndex) {
|
||||||
// 跳转商品列表
|
// 跳转商品列表
|
||||||
const arr = [];
|
const arr = [];
|
||||||
this.categoryBar.forEach((e, index) => {
|
this.categoryBar.forEach((e, index) => {
|
||||||
|
@ -189,7 +181,7 @@ export default {
|
||||||
});
|
});
|
||||||
return location.origin + "/goodsList?categoryId=" + arr.toString();
|
return location.origin + "/goodsList?categoryId=" + arr.toString();
|
||||||
},
|
},
|
||||||
async collect() {
|
async collect () {
|
||||||
// 收藏店铺
|
// 收藏店铺
|
||||||
if (this.storeCollected) {
|
if (this.storeCollected) {
|
||||||
let cancel = await cancelCollect("STORE", this.goodsMsg.data.storeId);
|
let cancel = await cancelCollect("STORE", this.goodsMsg.data.storeId);
|
||||||
|
|
|
@ -32,6 +32,10 @@ export const orderStatusList = [
|
||||||
{
|
{
|
||||||
name: '已取消',
|
name: '已取消',
|
||||||
status: 'CANCELLED'
|
status: 'CANCELLED'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '待提货',
|
||||||
|
status: 'STAY_PICKED_UP'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
// 订单售后状态
|
// 订单售后状态
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
></Step>
|
></Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
</div>
|
</div>
|
||||||
<div class="order-card">
|
<div class="order-card" v-if="order.order.deliveryMethod == 'LOGISTICS'">
|
||||||
<h3>收货人信息</h3>
|
<h3>收货人信息</h3>
|
||||||
<p>收货人:{{ order.order.consigneeName }}</p>
|
<p>收货人:{{ order.order.consigneeName }}</p>
|
||||||
<p>手机号码:{{ order.order.consigneeMobile | secrecyMobile }}</p>
|
<p>手机号码:{{ order.order.consigneeMobile | secrecyMobile }}</p>
|
||||||
|
@ -62,6 +62,11 @@
|
||||||
{{ order.order.consigneeDetail }}
|
{{ order.order.consigneeDetail }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="order-card" v-if="order.order.deliveryMethod == 'SELF_PICK_UP'">
|
||||||
|
<h3>自提点信息</h3>
|
||||||
|
<p>自提点名称:{{ order.order.storeAddressPath }}</p>
|
||||||
|
<p>联系方式:{{ order.order.storeAddressMobile }}</p>
|
||||||
|
</div>
|
||||||
<div class="order-card">
|
<div class="order-card">
|
||||||
<h3>付款信息</h3>
|
<h3>付款信息</h3>
|
||||||
<p>支付方式:{{ order.paymentMethodValue }}</p>
|
<p>支付方式:{{ order.paymentMethodValue }}</p>
|
||||||
|
@ -70,7 +75,7 @@
|
||||||
<div class="order-card" v-if="!order.order.verificationCode">
|
<div class="order-card" v-if="!order.order.verificationCode">
|
||||||
<h3>配送信息</h3>
|
<h3>配送信息</h3>
|
||||||
<p>配送方式:{{ order.deliveryMethodValue }}</p>
|
<p>配送方式:{{ order.deliveryMethodValue }}</p>
|
||||||
<p>配送状态:{{ order.deliverStatusValue }}</p>
|
<p v-if="order.order.deliveryMethod === 'LOGISTICS'">配送状态:{{ order.deliverStatusValue }}</p>
|
||||||
<p v-if="logistics">
|
<p v-if="logistics">
|
||||||
物流信息:{{ logistics.shipper || "暂无物流信息" }}
|
物流信息:{{ logistics.shipper || "暂无物流信息" }}
|
||||||
</p>
|
</p>
|
||||||
|
@ -270,6 +275,9 @@ export default {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.order = res.result;
|
this.order = res.result;
|
||||||
this.progressList = res.result.orderLogs;
|
this.progressList = res.result.orderLogs;
|
||||||
|
if (this.order.order.deliveryMethod === 'LOGISTICS') {
|
||||||
|
this.traces();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -336,7 +344,6 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getDetail();
|
this.getDetail();
|
||||||
this.traces();
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,42 +9,29 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="cart-steps">
|
<div class="cart-steps">
|
||||||
<span :class="stepIndex == 1 ? 'active' : ''">1.我的购物车</span>
|
<span :class="stepIndex == 1 ? 'active' : ''">1.我的购物车</span>
|
||||||
<Icon
|
<Icon :class="stepIndex == 1 ? 'active-arrow' : ''" custom="icomoon icon-next"></Icon>
|
||||||
:class="stepIndex == 1 ? 'active-arrow' : ''"
|
|
||||||
custom="icomoon icon-next"
|
|
||||||
></Icon>
|
|
||||||
<span :class="stepIndex == 1 ? 'active' : ''">2.填写订单信息</span>
|
<span :class="stepIndex == 1 ? 'active' : ''">2.填写订单信息</span>
|
||||||
<Icon
|
<Icon :class="stepIndex == 1 ? 'active-arrow' : ''" custom="icomoon icon-next"></Icon>
|
||||||
:class="stepIndex == 1 ? 'active-arrow' : ''"
|
|
||||||
custom="icomoon icon-next"
|
|
||||||
></Icon>
|
|
||||||
<span :class="stepIndex == 2 ? 'active' : ''">3.成功提交订单</span>
|
<span :class="stepIndex == 2 ? 'active' : ''">3.成功提交订单</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<div class="content width_1200">
|
<div class="content width_1200">
|
||||||
<!-- 收货地址 -->
|
<!-- 收货地址 -->
|
||||||
<div class="address">
|
<div class="address" v-if="selectedDeliverMethod === 'LOGISTICS'">
|
||||||
<div class="card-head">
|
<div class="card-head">
|
||||||
<span>收货人信息</span>
|
<span>收货人信息</span>
|
||||||
<span @click="goAddressManage">管理收货人地址</span>
|
<span @click="goAddressManage">管理收货人地址</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="address-manage">
|
<div class="address-manage">
|
||||||
<div
|
<div class="address-item" v-show="moreAddr ? true : index < 3"
|
||||||
class="address-item"
|
:class="selectedAddress.id === item.id ? 'border-red' : ''" @mouseenter="showEditBtn = index"
|
||||||
v-show="moreAddr ? true : index < 3"
|
@mouseleave="showEditBtn = ''" @click="selectAddress(item)" v-for="(item, index) in addressList"
|
||||||
:class="selectedAddress.id === item.id ? 'border-red' : ''"
|
:key="index">
|
||||||
@mouseenter="showEditBtn = index"
|
|
||||||
@mouseleave="showEditBtn = ''"
|
|
||||||
@click="selectAddress(item)"
|
|
||||||
v-for="(item, index) in addressList"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<span>{{ item.name }}</span>
|
<span>{{ item.name }}</span>
|
||||||
<Tag class="ml_10" v-if="item.isDefault" color="red">默认</Tag>
|
<Tag class="ml_10" v-if="item.isDefault" color="red">默认</Tag>
|
||||||
<Tag class="ml_10" v-if="item.alias" color="warning"
|
<Tag class="ml_10" v-if="item.alias" color="warning">{{ item.alias }}
|
||||||
>{{ item.alias }}
|
|
||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
<div>{{ item.mobile }}</div>
|
<div>{{ item.mobile }}</div>
|
||||||
|
@ -53,12 +40,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="edit-btn" v-show="showEditBtn === index">
|
<div class="edit-btn" v-show="showEditBtn === index">
|
||||||
<span @click.stop="editAddress(item.id)">修改</span>
|
<span @click.stop="editAddress(item.id)">修改</span>
|
||||||
<span
|
<span class="ml_10" v-if="!item.isDefault" @click.stop="delAddress(item)">删除</span>
|
||||||
class="ml_10"
|
|
||||||
v-if="!item.isDefault"
|
|
||||||
@click.stop="delAddress(item)"
|
|
||||||
>删除</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="corner-icon" v-show="selectedAddress.id === item.id">
|
<div class="corner-icon" v-show="selectedAddress.id === item.id">
|
||||||
<div></div>
|
<div></div>
|
||||||
|
@ -70,75 +52,99 @@
|
||||||
<div>添加新地址</div>
|
<div>添加新地址</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="more-addr" @click="moreAddr = !moreAddr" v-if="addressList.length > 3">
|
||||||
<div
|
|
||||||
class="more-addr"
|
|
||||||
@click="moreAddr = !moreAddr"
|
|
||||||
v-if="addressList.length > 3"
|
|
||||||
>
|
|
||||||
{{ moreAddr ? "收起地址" : "更多地址" }}
|
{{ moreAddr ? "收起地址" : "更多地址" }}
|
||||||
<Icon v-show="!moreAddr" type="md-arrow-dropdown" />
|
<Icon v-show="!moreAddr" type="md-arrow-dropdown" />
|
||||||
<Icon v-show="moreAddr" type="md-arrow-dropup" />
|
<Icon v-show="moreAddr" type="md-arrow-dropup" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="address" v-if="selectedDeliverMethod === 'SELF_PICK_UP'">
|
||||||
|
<div class="card-head">
|
||||||
|
<span>自提点信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="address-manage">
|
||||||
|
<div class="address-item" v-show="storeMoreAddr ? true : index < 3"
|
||||||
|
:class="selectedAddress.id === item.id ? 'border-red' : ''" @mouseenter="showEditBtn = index"
|
||||||
|
@mouseleave="showEditBtn = ''" @click="selectStoreAddress(item)" v-for="(item, index) in storeAddressList"
|
||||||
|
:key="index">
|
||||||
|
<div>
|
||||||
|
<span>{{ item.addressName }}</span>
|
||||||
|
</div>
|
||||||
|
<div>{{ item.mobile }}</div>
|
||||||
|
<div>
|
||||||
|
{{ item.address | unitAddress }} {{ item.detail }}
|
||||||
|
</div>
|
||||||
|
<div class="corner-icon" v-show="selectedStoreAddress.id === item.id">
|
||||||
|
<div></div>
|
||||||
|
<Icon type="md-checkmark" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="more-addr" @click="storeMoreAddr = !storeMoreAddr" v-if="addressList.length > 3">
|
||||||
|
{{ storeMoreAddr ? "收起地址" : "更多地址" }}
|
||||||
|
<Icon v-show="!storeMoreAddr" type="md-arrow-dropdown" />
|
||||||
|
<Icon v-show="storeMoreAddr" type="md-arrow-dropup" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
<div class="goods-content">
|
||||||
|
<div class="card-head mt_20 mb_20">
|
||||||
|
<span>配送方式</span>
|
||||||
|
</div>
|
||||||
|
<div class="delivery-method">
|
||||||
|
|
||||||
|
<div class="method-item" v-show="moreAddr ? true : index < 3"
|
||||||
|
:class="selectedDeliverMethod === item.value ? 'border-red' : ''" @mouseenter="showEditBtn = item.value"
|
||||||
|
@mouseleave="showEditBtn = ''" @click="selectDeliverMethod(item)" v-for="(item, index) in shippingMethod"
|
||||||
|
:key="index">
|
||||||
|
<div>{{ item.label }}</div>
|
||||||
|
<div class="corner-icon" v-show="selectedDeliverMethod === item.value">
|
||||||
|
<div></div>
|
||||||
|
<Icon type="md-checkmark" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 商品信息 -->
|
<!-- 商品信息 -->
|
||||||
<div class="goods-content">
|
<div class="goods-content">
|
||||||
<div class="card-head mt_20 mb_20">
|
<div class="card-head mt_20 mb_20">
|
||||||
<span>商品信息</span>
|
<span>商品信息</span>
|
||||||
<span @click="$router.push('/cart')">返回购物车</span>
|
<span @click="$router.push('/cart')">返回购物车</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="goods-msg" v-for="(shop, shopIndex) in goodsList" :key="shopIndex">
|
||||||
class="goods-msg"
|
|
||||||
v-for="(shop, shopIndex) in goodsList"
|
|
||||||
:key="shopIndex"
|
|
||||||
>
|
|
||||||
<div v-if="shop.checked">
|
<div v-if="shop.checked">
|
||||||
<div class="shop-name">
|
<div class="shop-name">
|
||||||
<span>
|
<span>
|
||||||
<span class="hover-color" @click="goShopPage(shop.storeId)">{{
|
<span class="hover-color" @click="goShopPage(shop.storeId)">{{
|
||||||
shop.storeName
|
shop.storeName
|
||||||
}}</span
|
}}</span>
|
||||||
>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="goods-list">
|
<div class="goods-list">
|
||||||
<div
|
<div class="goods-item" v-for="(goods, goodsIndex) in shop.checkedSkuList" :key="goodsIndex">
|
||||||
class="goods-item"
|
<span class="hover-color" @click="
|
||||||
v-for="(goods, goodsIndex) in shop.checkedSkuList"
|
goGoodsDetail(goods.goodsSku.id, goods.goodsSku.goodsId)
|
||||||
:key="goodsIndex"
|
">
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="hover-color"
|
|
||||||
@click="
|
|
||||||
goGoodsDetail(goods.goodsSku.id, goods.goodsSku.goodsId)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<img :src="goods.goodsSku.thumbnail" alt="" />
|
<img :src="goods.goodsSku.thumbnail" alt="" />
|
||||||
<span style="vertical-align: top">{{
|
<span style="vertical-align: top">{{
|
||||||
goods.goodsSku.goodsName
|
goods.goodsSku.goodsName
|
||||||
}}</span>
|
}}</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="goods-price">{{
|
<span class="goods-price">{{
|
||||||
goods.purchasePrice | unitPrice("¥")
|
goods.purchasePrice | unitPrice("¥")
|
||||||
}}</span>
|
}}</span>
|
||||||
<span>x{{ goods.num }}</span>
|
<span>x{{ goods.num }}</span>
|
||||||
<span>{{ goods.goodsSku.quantity > 0 ? "有货" : "无货" }}</span>
|
<span>{{ goods.goodsSku.quantity > 0 ? "有货" : "无货" }}</span>
|
||||||
<span class="goods-price">{{
|
<span class="goods-price">{{
|
||||||
goods.subTotal | unitPrice("¥")
|
goods.subTotal | unitPrice("¥")
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="order-mark">
|
<div class="order-mark">
|
||||||
<Input
|
<Input type="textarea" maxlength="60" v-model="shop.remark" show-word-limit placeholder="订单备注" />
|
||||||
type="textarea"
|
<span style="font-size: 12px; color: #999">提示:请勿填写有关支付、收货、发票方面的信息</span>
|
||||||
maxlength="60"
|
|
||||||
v-model="shop.remark"
|
|
||||||
show-word-limit
|
|
||||||
placeholder="订单备注"
|
|
||||||
/>
|
|
||||||
<span style="font-size: 12px; color: #999"
|
|
||||||
>提示:请勿填写有关支付、收货、发票方面的信息</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -146,13 +152,9 @@
|
||||||
<!-- 发票信息 -->
|
<!-- 发票信息 -->
|
||||||
<div class="invoice">
|
<div class="invoice">
|
||||||
<div class="card-head mt_20 mb_20">
|
<div class="card-head mt_20 mb_20">
|
||||||
<span class="relative"
|
<span class="relative">发票信息<span class="inv-tips">
|
||||||
>发票信息<span class="inv-tips">
|
<Icon type="ios-alert-outline" />开企业抬头发票须填写纳税人识别号,以免影响报销
|
||||||
<Icon
|
</span></span>
|
||||||
type="ios-alert-outline"
|
|
||||||
/>开企业抬头发票须填写纳税人识别号,以免影响报销
|
|
||||||
</span></span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="inovice-content">
|
<div class="inovice-content">
|
||||||
<span>{{ invoiceData.receiptTitle }}</span>
|
<span>{{ invoiceData.receiptTitle }}</span>
|
||||||
|
@ -167,47 +169,24 @@
|
||||||
</div>
|
</div>
|
||||||
<div v-if="couponList.length === 0">无可用优惠券</div>
|
<div v-if="couponList.length === 0">无可用优惠券</div>
|
||||||
<ul v-else class="coupon-list">
|
<ul v-else class="coupon-list">
|
||||||
<li
|
<li v-for="(item, index) in couponList" class="coupon-item" :key="index">
|
||||||
v-for="(item, index) in couponList"
|
|
||||||
class="coupon-item"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<div class="c-left">
|
<div class="c-left">
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span v-if="item.couponType === 'PRICE'" class="fontsize_12 global_color">¥<span class="price">{{
|
||||||
v-if="item.couponType === 'PRICE'"
|
|
||||||
class="fontsize_12 global_color"
|
|
||||||
>¥<span class="price">{{
|
|
||||||
item.price | unitPrice
|
item.price | unitPrice
|
||||||
}}</span></span
|
}}</span></span>
|
||||||
>
|
<span v-if="item.couponType === 'DISCOUNT'" class="fontsize_12 global_color"><span class="price">{{
|
||||||
<span
|
item.discount
|
||||||
v-if="item.couponType === 'DISCOUNT'"
|
}}</span>折</span>
|
||||||
class="fontsize_12 global_color"
|
<span class="describe">满{{ item.consumeThreshold }}元可用</span>
|
||||||
><span class="price">{{ item.discount }}</span
|
|
||||||
>折</span
|
|
||||||
>
|
|
||||||
<span class="describe"
|
|
||||||
>满{{ item.consumeThreshold }}元可用</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<p>使用范围:{{ useScope(item.scopeType) }}</p>
|
<p>使用范围:{{ useScope(item.scopeType) }}</p>
|
||||||
<p>有效期:{{ item.endTime }}</p>
|
<p>有效期:{{ item.endTime }}</p>
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img class="used" v-if="usedCouponId.includes(item.id)" src="../../assets/images/geted.png" alt="" />
|
||||||
class="used"
|
|
||||||
v-if="usedCouponId.includes(item.id)"
|
|
||||||
src="../../assets/images/geted.png"
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<b></b>
|
<b></b>
|
||||||
<a class="c-right" @click="useCoupon(item.id, true)">立即使用</a>
|
<a class="c-right" @click="useCoupon(item.id, true)">立即使用</a>
|
||||||
<a
|
<a class="c-right" v-if="usedCouponId.includes(item.id)" @click="useCoupon(item.id, false)">放弃优惠</a>
|
||||||
class="c-right"
|
|
||||||
v-if="usedCouponId.includes(item.id)"
|
|
||||||
@click="useCoupon(item.id, false)"
|
|
||||||
>放弃优惠</a
|
|
||||||
>
|
|
||||||
<i class="circle-top"></i>
|
<i class="circle-top"></i>
|
||||||
<i class="circle-bottom"></i>
|
<i class="circle-bottom"></i>
|
||||||
</li>
|
</li>
|
||||||
|
@ -216,30 +195,24 @@
|
||||||
<!-- 订单价格 -->
|
<!-- 订单价格 -->
|
||||||
<div class="order-price">
|
<div class="order-price">
|
||||||
<div>
|
<div>
|
||||||
<span>{{ totalNum }}件商品,总商品金额:</span
|
<span>{{ totalNum }}件商品,总商品金额:</span><span>{{ priceDetailDTO.goodsPrice | unitPrice("¥") }}</span>
|
||||||
><span>{{ priceDetailDTO.goodsPrice | unitPrice("¥") }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="priceDetailDTO.freightPrice > 0">
|
<div v-if="priceDetailDTO.freightPrice > 0">
|
||||||
<span>运费:</span
|
<span>运费:</span><span>{{ priceDetailDTO.freightPrice | unitPrice("¥") }}</span>
|
||||||
><span>{{ priceDetailDTO.freightPrice | unitPrice("¥") }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="priceDetailDTO.discountPrice > 0">
|
<div v-if="priceDetailDTO.discountPrice > 0">
|
||||||
<span>优惠金额:</span
|
<span>优惠金额:</span><span>-{{ priceDetailDTO.discountPrice | unitPrice("¥") }}</span>
|
||||||
><span>-{{ priceDetailDTO.discountPrice | unitPrice("¥") }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="priceDetailDTO.couponPrice > 0">
|
<div v-if="priceDetailDTO.couponPrice > 0">
|
||||||
<span>优惠券金额:</span
|
<span>优惠券金额:</span><span>-{{ priceDetailDTO.couponPrice | unitPrice("¥") }}</span>
|
||||||
><span>-{{ priceDetailDTO.couponPrice | unitPrice("¥") }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="$route.query.way === 'POINTS'">
|
<div v-if="$route.query.way === 'POINTS'">
|
||||||
<span>应付积分:</span
|
<span>应付积分:</span><span class="actrual-price">{{ priceDetailDTO.payPoint }}</span>
|
||||||
><span class="actrual-price">{{ priceDetailDTO.payPoint }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<span>应付金额:</span
|
<span>应付金额:</span><span class="actrual-price">{{
|
||||||
><span class="actrual-price">{{
|
priceDetailDTO.flowPrice | unitPrice("¥")
|
||||||
priceDetailDTO.flowPrice | unitPrice("¥")
|
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -250,23 +223,15 @@
|
||||||
<div class="pay-address" v-if="addressList.length">
|
<div class="pay-address" v-if="addressList.length">
|
||||||
配送至:{{ selectedAddress.consigneeAddressPath | unitAddress }}
|
配送至:{{ selectedAddress.consigneeAddressPath | unitAddress }}
|
||||||
{{ selectedAddress.detail }} 收货人:{{
|
{{ selectedAddress.detail }} 收货人:{{
|
||||||
selectedAddress.name
|
selectedAddress.name
|
||||||
}} {{ selectedAddress.mobile }}
|
}} {{ selectedAddress.mobile }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<BaseFooter></BaseFooter>
|
<BaseFooter></BaseFooter>
|
||||||
<!-- 添加发票模态框 -->
|
<!-- 添加发票模态框 -->
|
||||||
<invoice-modal
|
<invoice-modal ref="invModal" :invoiceData="invoiceData" @change="getInvMsg" />
|
||||||
ref="invModal"
|
|
||||||
:invoiceData="invoiceData"
|
|
||||||
@change="getInvMsg"
|
|
||||||
/>
|
|
||||||
<!-- 选择地址模态框 -->
|
<!-- 选择地址模态框 -->
|
||||||
<address-manage
|
<address-manage ref="address" :id="addrId" @change="addrChange"></address-manage>
|
||||||
ref="address"
|
|
||||||
:id="addrId"
|
|
||||||
@change="addrChange"
|
|
||||||
></address-manage>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -279,8 +244,12 @@ import {
|
||||||
createTrade,
|
createTrade,
|
||||||
selectAddr,
|
selectAddr,
|
||||||
selectCoupon,
|
selectCoupon,
|
||||||
|
setShipMethod,
|
||||||
|
setStoreAddressId,
|
||||||
|
shippingMethodList,
|
||||||
couponNum,
|
couponNum,
|
||||||
} from "@/api/cart";
|
} from "@/api/cart";
|
||||||
|
import { getStoreAddress } from "@/api/shopentry.js"
|
||||||
import { canUseCouponList } from "@/api/member.js";
|
import { canUseCouponList } from "@/api/member.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -288,15 +257,35 @@ export default {
|
||||||
components: { invoiceModal, addressManage },
|
components: { invoiceModal, addressManage },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
selectedStoreAddress: 'm',
|
||||||
|
selectMethod: '',
|
||||||
stepIndex: 1, // 顶部步骤条状态
|
stepIndex: 1, // 顶部步骤条状态
|
||||||
invoiceAvailable: false, // 发票编辑按钮
|
invoiceAvailable: false, // 发票编辑按钮
|
||||||
showEditBtn: "", // 鼠标移入显示编辑按钮
|
showEditBtn: "", // 鼠标移入显示编辑按钮
|
||||||
orderMark: "", // 订单备注
|
orderMark: "", // 订单备注
|
||||||
|
storeMoreAddr: false,
|
||||||
invoiceData: {
|
invoiceData: {
|
||||||
// 发票数据
|
// 发票数据
|
||||||
receiptTitle: "个人",
|
receiptTitle: "个人",
|
||||||
receiptContent: "不开发票",
|
receiptContent: "不开发票",
|
||||||
},
|
},
|
||||||
|
searchForm: {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 100
|
||||||
|
},
|
||||||
|
shippingMethod: [],
|
||||||
|
storeAddressList: [],
|
||||||
|
shippingWay: [
|
||||||
|
{
|
||||||
|
value: "LOGISTICS",
|
||||||
|
label: "物流",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "SELF_PICK_UP",
|
||||||
|
label: "自提",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
selectedDeliverMethod: 'LOGISTICS',
|
||||||
addressList: [], // 地址列表
|
addressList: [], // 地址列表
|
||||||
selectedAddress: {}, // 所选地址
|
selectedAddress: {}, // 所选地址
|
||||||
goodsList: [], // 商品列表
|
goodsList: [], // 商品列表
|
||||||
|
@ -308,6 +297,7 @@ export default {
|
||||||
couponList: [], // 可用优惠券列表
|
couponList: [], // 可用优惠券列表
|
||||||
usedCouponId: [], // 已使用优惠券id
|
usedCouponId: [], // 已使用优惠券id
|
||||||
selectedCoupon: {}, // 已选优惠券对象
|
selectedCoupon: {}, // 已选优惠券对象
|
||||||
|
storeId: '', //店铺Id
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -317,6 +307,7 @@ export default {
|
||||||
// 初始化数据
|
// 初始化数据
|
||||||
init() {
|
init() {
|
||||||
this.getGoodsDetail();
|
this.getGoodsDetail();
|
||||||
|
this.getDistribution();
|
||||||
},
|
},
|
||||||
goAddressManage() {
|
goAddressManage() {
|
||||||
// 跳转地址管理页面
|
// 跳转地址管理页面
|
||||||
|
@ -324,7 +315,7 @@ export default {
|
||||||
},
|
},
|
||||||
getAddress() {
|
getAddress() {
|
||||||
// 获取收货地址列表
|
// 获取收货地址列表
|
||||||
memberAddress().then((res) => {
|
memberAddress(this.searchForm).then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.addressList = res.result.records;
|
this.addressList = res.result.records;
|
||||||
this.addressList.forEach((e, index) => {
|
this.addressList.forEach((e, index) => {
|
||||||
|
@ -335,6 +326,38 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 获取配送方式列表
|
||||||
|
async getDistribution() {
|
||||||
|
let shopRes = await shippingMethodList({ way: this.$route.query.way });
|
||||||
|
let shopList;
|
||||||
|
if (shopRes.success) {
|
||||||
|
shopList = shopRes.result;
|
||||||
|
let way = [];
|
||||||
|
console.log(shopList)
|
||||||
|
this.shippingWay.forEach((item) => {
|
||||||
|
shopList.forEach((child) => {
|
||||||
|
if (item.value == child) {
|
||||||
|
way.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.shippingMethod = way;
|
||||||
|
console.log(this.shippingMethod)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getStoreAddressList() {
|
||||||
|
getStoreAddress(this.storeId,this.searchForm).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
this.storeAddressList = res.result.records
|
||||||
|
this.storeAddressList.forEach((e, index) => {
|
||||||
|
if (e.id === this.selectedAddress.id && index > 2) {
|
||||||
|
this.storeMoreAddr = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
getGoodsDetail() {
|
getGoodsDetail() {
|
||||||
// 订单商品详情
|
// 订单商品详情
|
||||||
this.$Spin.show();
|
this.$Spin.show();
|
||||||
|
@ -364,7 +387,7 @@ export default {
|
||||||
this.goodsList = res.result.cartList;
|
this.goodsList = res.result.cartList;
|
||||||
this.priceDetailDTO = res.result.priceDetailDTO;
|
this.priceDetailDTO = res.result.priceDetailDTO;
|
||||||
this.skuList = res.result.skuList;
|
this.skuList = res.result.skuList;
|
||||||
|
this.storeId = this.goodsList[0].storeId
|
||||||
if (res.result.receiptVO) {
|
if (res.result.receiptVO) {
|
||||||
this.invoiceData = res.result.receiptVO;
|
this.invoiceData = res.result.receiptVO;
|
||||||
}
|
}
|
||||||
|
@ -401,6 +424,7 @@ export default {
|
||||||
this.selectedAddress = res.result.memberAddress;
|
this.selectedAddress = res.result.memberAddress;
|
||||||
}
|
}
|
||||||
this.getAddress();
|
this.getAddress();
|
||||||
|
this.getStoreAddressList();
|
||||||
this.totalNum = 0;
|
this.totalNum = 0;
|
||||||
for (let i = 0; i < this.skuList.length; i++) {
|
for (let i = 0; i < this.skuList.length; i++) {
|
||||||
this.totalNum += this.skuList[i].num;
|
this.totalNum += this.skuList[i].num;
|
||||||
|
@ -475,8 +499,32 @@ export default {
|
||||||
};
|
};
|
||||||
selectAddr(params).then((res) => {
|
selectAddr(params).then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.$Message.success("选择收货地址成功");
|
this.$Message.success("选择配送方式成功");
|
||||||
this.selectedAddress = item;
|
this.selectMethod = item;
|
||||||
|
this.getGoodsDetail();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selectStoreAddress(item) {
|
||||||
|
console.log(item.id)
|
||||||
|
console.log(this.$route.query.way)
|
||||||
|
// 选择自提地址
|
||||||
|
setStoreAddressId(item.id,this.$route.query.way).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
this.$Message.success("选择自提地址成功");
|
||||||
|
this.selectedStoreAddress = item;
|
||||||
|
this.getGoodsDetail();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selectDeliverMethod(item) {
|
||||||
|
let params = {
|
||||||
|
way: this.$route.query.way,
|
||||||
|
shippingMethod: item.value,
|
||||||
|
};
|
||||||
|
setShipMethod(params).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
this.selectedDeliverMethod = item.value;
|
||||||
this.getGoodsDetail();
|
this.getGoodsDetail();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -503,7 +551,7 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onCancel: () => {},
|
onCancel: () => { },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
goGoodsDetail(skuId, goodsId) {
|
goGoodsDetail(skuId, goodsId) {
|
||||||
|
@ -605,9 +653,11 @@ export default {
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "../../assets/styles/coupon.scss";
|
@import "../../assets/styles/coupon.scss";
|
||||||
|
|
||||||
.goods-msg {
|
.goods-msg {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** logo start */
|
/** logo start */
|
||||||
.logo {
|
.logo {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
@ -680,12 +730,82 @@ export default {
|
||||||
padding: 15px 25px;
|
padding: 15px 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.delivery-method {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
border: 1px dotted #949494;
|
||||||
|
width: 50px;
|
||||||
|
height: 40px;
|
||||||
|
margin: 20px 20px 0 0;
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-item {
|
||||||
|
position: relative;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
>div:nth-child(1) {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>span:nth-child(1) {
|
||||||
|
color: #000000;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-btn {
|
||||||
|
font-size: 12px;
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 20px;
|
||||||
|
color: $theme_color;
|
||||||
|
|
||||||
|
span:hover {
|
||||||
|
border-bottom: 1px solid $theme_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.corner-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: -1px;
|
||||||
|
bottom: -1px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
width: 0;
|
||||||
|
border-top: 20px solid transparent;
|
||||||
|
border-right: 20px solid $theme_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ivu-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 1px;
|
||||||
|
transform: rotate(-15deg);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-red {
|
||||||
|
border-color: $theme_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 地址管理 */
|
/** 地址管理 */
|
||||||
.address-manage {
|
.address-manage {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
> div {
|
>div {
|
||||||
border: 1px dotted #949494;
|
border: 1px dotted #949494;
|
||||||
width: 265px;
|
width: 265px;
|
||||||
height: 120px;
|
height: 120px;
|
||||||
|
@ -704,20 +824,21 @@ export default {
|
||||||
.ivu-icon {
|
.ivu-icon {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.address-item {
|
.address-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
||||||
> div:nth-child(1) {
|
>div:nth-child(1) {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> span:nth-child(1) {
|
>span:nth-child(1) {
|
||||||
color: #000000;
|
color: #000000;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
@ -767,7 +888,7 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
> span:nth-child(1) {
|
>span:nth-child(1) {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
.ivu-icon {
|
.ivu-icon {
|
||||||
|
@ -779,7 +900,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> span:nth-child(2) {
|
>span:nth-child(2) {
|
||||||
color: #999;
|
color: #999;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -833,22 +954,23 @@ export default {
|
||||||
height: 48px;
|
height: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> span {
|
>span {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> span:nth-child(1) {
|
>span:nth-child(1) {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
> span {
|
|
||||||
|
>span {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> span:last-child {
|
>span:last-child {
|
||||||
color: $theme_color;
|
color: $theme_color;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
@ -895,11 +1017,11 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.inovice-content {
|
.inovice-content {
|
||||||
> span {
|
>span {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> span:last-child {
|
>span:last-child {
|
||||||
color: $theme_color;
|
color: $theme_color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
@ -919,7 +1041,7 @@ export default {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #999;
|
color: #999;
|
||||||
|
|
||||||
> div > span:nth-child(2) {
|
>div>span:nth-child(2) {
|
||||||
width: 130px;
|
width: 130px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
NODE_ENV=production
|
||||||
|
VUE_APP_PREVIEW=false
|
||||||
|
VUE_APP_API_BASE_URL=https://im-api.pickmall.cn
|
||||||
|
VUE_APP_WEB_SOCKET_URL=wss://im-api.pickmall.cn/lili/webSocket
|
||||||
|
VUE_APP_COMMON=https://common-api.pickmall.cn
|
||||||
|
VUE_APP_WEBSITE_NAME="LiLi IM"
|
||||||
|
VUE_APP_PC_ORDER_URL=https://store-b2b2c.pickmall.cn
|
|
@ -0,0 +1,7 @@
|
||||||
|
NODE_ENV=development
|
||||||
|
VUE_APP_PREVIEW=true
|
||||||
|
VUE_APP_API_BASE_URL=http://192.168.0.113:8885
|
||||||
|
VUE_APP_WEB_SOCKET_URL=ws://192.168.0.113:8885/lili/webSocket
|
||||||
|
VUE_APP_COMMON=http://192.168.0.113:8890
|
||||||
|
VUE_APP_PC_URL="http://192.168.0.113:10001"
|
||||||
|
VUE_APP_WEBSITE_NAME="LiLi IM"
|
|
@ -0,0 +1,23 @@
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 YuanDong
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,71 @@
|
||||||
|
# Springboot-websocket
|
||||||
|
|
||||||
|
过渡阶段IM
|
||||||
|
|
||||||
|
前端仓库:https://gitee.com/beijing_hongye_huicheng/im
|
||||||
|
|
||||||
|
后端仓库:https://gitee.com/beijing_hongye_huicheng/springboot-websocket
|
||||||
|
|
||||||
|
部署方式:
|
||||||
|
1、导入数据库,配置resource目录下application.yml的数据库以及redis配置文件。
|
||||||
|
|
||||||
|
2、maven打包
|
||||||
|
|
||||||
|
3、启动jar包即可。
|
||||||
|
|
||||||
|
4、前端程序运行,测试环境需配置根目录 .env.development文件,正式环境需配置 .env 文件。
|
||||||
|
|
||||||
|
# 参考项目
|
||||||
|
项目前端参考:https://gitee.com/gzydong/LumenIM.git 功能更丰富,大家可以去学习一波
|
||||||
|
|
||||||
|
|
||||||
|
# IM体验
|
||||||
|
浏览器1打开地址:http://127.0.0.1:8000/message?token=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyQ29udGV4dCI6IntcInVzZXJuYW1lXCI6XCIxMzAxMTExMTExMVwiLFwibmlja05hbWVcIjpcIuW8oOS4ieWTiOWTiOWTiFwiLFwiZmFjZVwiOlwiaHR0cHM6Ly9saWxpc2hvcC1vc3Mub3NzLWNuLWJlaWppbmcuYWxpeXVuY3MuY29tLzQ1ZDUyOGYwMjRjZTQyMzI4NzYxNjFhZmQxN2Y0ZWExLmpwZ1wiLFwiaWRcIjpcIjEzNzY0MTc2ODQxNDAzMjY5MTJcIixcImxvbmdUZXJtXCI6ZmFsc2UsXCJyb2xlXCI6XCJTVE9SRVwiLFwic3RvcmVJZFwiOlwiMTM3NjQzMzU2NTI0NzQ3MTYxNlwiLFwic3RvcmVOYW1lXCI6XCLlrrblrrbkuZBcIixcImlzU3VwZXJcIjpmYWxzZX0iLCJzdWIiOiIxMzAxMTExMTExMSIsImV4cCI6MTY0NTQ2OTk1M30.fXpCZ2YiFYqACpmxVvKjIpXovfPRDJavHjftpQzdEps
|
||||||
|
|
||||||
|
浏览器2打开地址:http://127.0.0.1:8000/message?token=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyQ29udGV4dCI6IntcInVzZXJuYW1lXCI6XCIxMzAxMTExMTExMVwiLFwibmlja05hbWVcIjpcIuW8oOS4ieWTiOWTiOWTiFwiLFwiZmFjZVwiOlwiaHR0cHM6Ly9saWxpc2hvcC1vc3Mub3NzLWNuLWJlaWppbmcuYWxpeXVuY3MuY29tLzk2N2UzMzU1Yzg0NTRiNGFhMTk1N2M1NTQ5ZTZiNzIwLnBuZ1wiLFwiaWRcIjpcIjEzNzY0MTc2ODQxNDAzMjY5MTJcIixcImxvbmdUZXJtXCI6ZmFsc2UsXCJyb2xlXCI6XCJNRU1CRVJcIixcImlzU3VwZXJcIjpmYWxzZX0iLCJzdWIiOiIxMzAxMTExMTExMSIsImV4cCI6MTY0NTQ2OTAyNn0.GEkGpKRKF3rqzHRhaPCFilPpWe37cIXTT4KnwWR4Bt0&id=1376433565247471616
|
||||||
|
|
||||||
|
即可进行聊天。
|
||||||
|
|
||||||
|
# NGINX配置事例
|
||||||
|
线上NGINX配置在测试阶段出现问题,这里吧相关的配置贴出来供大家参考。
|
||||||
|
````
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
|
||||||
|
ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
|
||||||
|
ssl_session_cache shared:SSL:1m;
|
||||||
|
ssl_session_timeout 10m;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
include /etc/nginx/default.d/*.conf;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
server_name im-api.pickmall.cn;
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8088;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
|
||||||
|
ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
|
||||||
|
ssl_session_cache shared:SSL:1m;
|
||||||
|
ssl_session_timeout 10m;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
include /etc/nginx/default.d/*.conf;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header REMOTE-HOST $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
server_name im.pickmall.cn;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
root /home/im/im/dist;
|
||||||
|
}
|
||||||
|
````
|
|
@ -0,0 +1,51 @@
|
||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
"import",
|
||||||
|
{
|
||||||
|
"libraryName": "element-ui",
|
||||||
|
"styleLibraryName": "theme-chalk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"prismjs",
|
||||||
|
{
|
||||||
|
"languages": [
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"less",
|
||||||
|
"javascript",
|
||||||
|
"typescript",
|
||||||
|
"json",
|
||||||
|
"xml",
|
||||||
|
"bash",
|
||||||
|
"nginx",
|
||||||
|
"sql",
|
||||||
|
"docker",
|
||||||
|
"php",
|
||||||
|
"java",
|
||||||
|
"go",
|
||||||
|
"python",
|
||||||
|
"ruby",
|
||||||
|
"rust",
|
||||||
|
"objectivec",
|
||||||
|
"c",
|
||||||
|
"csharp",
|
||||||
|
"cpp",
|
||||||
|
"lua",
|
||||||
|
"shell",
|
||||||
|
"vim",
|
||||||
|
"yaml",
|
||||||
|
"yml",
|
||||||
|
"md",
|
||||||
|
"erlang",
|
||||||
|
"ini"
|
||||||
|
],
|
||||||
|
"theme": "okaidia"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"name": "LiLi-IM",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vue-cli-service serve",
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.21.4",
|
||||||
|
"babel-plugin-prismjs": "^2.0.1",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"element-ui": "^2.14.1",
|
||||||
|
"js-audio-recorder": "^1.0.6",
|
||||||
|
"js-base64": "^2.5.1",
|
||||||
|
"mavon-editor": "^2.10.4",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
|
"prismjs": "^1.29.0",
|
||||||
|
"svg-sprite-loader": "^5.0.0",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-contextmenujs": "^1.3.13",
|
||||||
|
"vue-cropper": "^0.5.5",
|
||||||
|
"vue-prism-editor": "^0.5.1",
|
||||||
|
"vue-router": "^3.4.9",
|
||||||
|
"vuex": "^3.5.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "^5.0.8",
|
||||||
|
"@vue/cli-plugin-eslint": "^5.0.8",
|
||||||
|
"@vue/cli-service": "^5.0.8",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"babel-plugin-import": "^1.13.1",
|
||||||
|
"compression-webpack-plugin": "^5.0.0",
|
||||||
|
"eslint": "^8.28.0",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"less": "^3.0.4",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"postcss": "^8.4.20",
|
||||||
|
"style-resources-loader": "^1.4.1",
|
||||||
|
"vue-cli-plugin-style-resources-loader": "^0.1.4",
|
||||||
|
"vue-svg-component-runtime": "^1.0.1",
|
||||||
|
"vue-svg-icon-loader": "^2.1.1",
|
||||||
|
"vue-template-compiler": "^2.6.11",
|
||||||
|
"webpack": "^5.75.0"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
},
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not dead"
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cmn-Hans">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover">
|
||||||
|
<link rel="icon" href="favicon.ico">
|
||||||
|
<title>LiLi IM</title>
|
||||||
|
<style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
|
||||||
|
<!-- require cdn assets css -->
|
||||||
|
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
|
||||||
|
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
|
||||||
|
<% } %>
|
||||||
|
<link rel="stylesheet" href="https://at.alicdn.com/t/font_1425251_3v0kq1by4iq.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.bootcss.com/animate.css/3.7.2/animate.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app">
|
||||||
|
<div class="first-loading-wrp">
|
||||||
|
<div class="loading-wrp">
|
||||||
|
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- require cdn assets js -->
|
||||||
|
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
|
||||||
|
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
|
||||||
|
<% } %>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<router-view v-if="showView" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
// 用于点击当前页的router时,刷新当前页
|
||||||
|
showView: true,
|
||||||
|
beforeUnload: '',
|
||||||
|
Handler: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 刷新当前路由方法
|
||||||
|
refreshView () {
|
||||||
|
this.showView = false
|
||||||
|
this.$nextTick(() => (this.showView = true))
|
||||||
|
},
|
||||||
|
beforeunloadHandler () {
|
||||||
|
this.beforeUnload = new Date().getTime();
|
||||||
|
},
|
||||||
|
// 页面关闭后 重置btnHide
|
||||||
|
unloadHandler (e) {
|
||||||
|
this.Handler = new Date().getTime() - this.beforeUnload;
|
||||||
|
if (this.Handler <= 5) {
|
||||||
|
var storage = window.localStorage;
|
||||||
|
storage.clear()
|
||||||
|
localStorage.setItem('btnHide', 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
window.addEventListener('beforeunload', e => this.beforeunloadHandler(e))
|
||||||
|
window.addEventListener('unload', e => this.unloadHandler(e))
|
||||||
|
},
|
||||||
|
destroyed () {
|
||||||
|
window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e))
|
||||||
|
window.removeEventListener('unload', e => this.unloadHandler(e))
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,109 @@
|
||||||
|
import { post, get, upload, del } from "@/utils/request";
|
||||||
|
|
||||||
|
// 获取聊天列表服务接口
|
||||||
|
export const ServeGetTalkList = (data) => {
|
||||||
|
return get("/im/talk/list", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取聊天列表服务接口
|
||||||
|
export const ServeGetStoreTalkList = (data) => {
|
||||||
|
return get("/im/talk/store/list", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 聊天列表创建服务接口
|
||||||
|
export const ServeCreateTalkList = (id) => {
|
||||||
|
return get(`/im/talk/user/${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除聊天列表服务接口
|
||||||
|
export const ServeDeleteTalkList = (data) => {
|
||||||
|
return del("/im/talk", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 对话列表置顶服务接口
|
||||||
|
export const ServeTopTalkList = (data) => {
|
||||||
|
return post("/im/talk/top", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清除聊天消息未读数服务接口
|
||||||
|
export const ServeClearTalkUnreadNum = (data) => {
|
||||||
|
return post("/im/talk/update-unread-num", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取聊天记录服务接口
|
||||||
|
export const ServeTalkRecords = (data) => {
|
||||||
|
return get("/im/message", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取转发会话记录详情列表服务接口
|
||||||
|
export const ServeGetForwardRecords = (data) => {
|
||||||
|
return get("/im/talk/get-forward-records", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 对话列表置顶服务接口
|
||||||
|
export const ServeSetNotDisturb = (data) => {
|
||||||
|
return post("/im/talk/disturb", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查找用户聊天记录服务接口
|
||||||
|
export const ServeFindTalkRecords = (data) => {
|
||||||
|
return get("/im/talk/find-chat-records", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 搜索用户聊天记录服务接口
|
||||||
|
export const ServeSearchTalkRecords = (data) => {
|
||||||
|
return get("/im/talk/search-chat-records", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ServeGetRecordsContext = (data) => {
|
||||||
|
return get("/im/talk/get-records-context", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送代码块消息服务接口
|
||||||
|
export const ServeSendTalkCodeBlock = (data) => {
|
||||||
|
return post("/im/talk/message/code", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送聊天文件服务接口
|
||||||
|
export const ServeSendTalkFile = (data) => {
|
||||||
|
return post("/im/talk/message/file", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送聊天图片服务接口
|
||||||
|
export const ServeSendTalkImage = (data) => {
|
||||||
|
return upload("/common/common/upload/file", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送表情包服务接口
|
||||||
|
export const ServeSendEmoticon = (data) => {
|
||||||
|
return post("/im/talk/message/emoticon", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 转发消息服务接口
|
||||||
|
export const ServeForwardRecords = (data) => {
|
||||||
|
return post("/im/talk/message/forward", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 撤回消息服务接口
|
||||||
|
export const ServeRevokeRecords = (data) => {
|
||||||
|
return post("/im/talk/message/revoke", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除消息服务接口
|
||||||
|
export const ServeRemoveRecords = (data) => {
|
||||||
|
return post("/im/talk/message/delete", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 收藏表情包服务接口
|
||||||
|
export const ServeCollectEmoticon = (data) => {
|
||||||
|
return post("/im/talk/message/collect", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
//投票
|
||||||
|
export const ServeSendVote = (data) => {
|
||||||
|
return post("/im/talk/message/vote", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ServeConfirmVoteHandle = (data) => {
|
||||||
|
return post("/im/talk/message/vote/handle", data);
|
||||||
|
};
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { post, get } from '@/utils/request'
|
||||||
|
|
||||||
|
// 获取好友列表服务接口
|
||||||
|
export const ServeGetContacts = data => {
|
||||||
|
return get('/contacts/list', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解除好友关系服务接口
|
||||||
|
export const ServeDeleteContact = data => {
|
||||||
|
return post('/contacts/delete', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改好友备注服务接口
|
||||||
|
export const ServeEditContactRemark = data => {
|
||||||
|
return post('/contacts/edit-remark', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索联系人
|
||||||
|
export const ServeSearchContact = data => {
|
||||||
|
return get('/contacts/search', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 好友申请服务接口
|
||||||
|
export const ServeCreateContact = data => {
|
||||||
|
return post('/contacts/apply/create', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询好友申请服务接口
|
||||||
|
export const ServeGetContactApplyRecords = data => {
|
||||||
|
return get('/contacts/apply/records', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理好友申请服务接口
|
||||||
|
export const ServeApplyAccept = data => {
|
||||||
|
return post('/contacts/apply/accept', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ServeApplyDecline = data => {
|
||||||
|
return post('/contacts/apply/decline', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询好友申请未读数量服务接口
|
||||||
|
export const ServeFindFriendApplyNum = () => {
|
||||||
|
return get('/contacts/apply-unread-num')
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { post, get, upload } from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询用户表情包服务接口
|
||||||
|
export const ServeFindUserEmoticon = () => {
|
||||||
|
return get('/emoticon/list')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询系统表情包服务接口
|
||||||
|
export const ServeFindSysEmoticon = () => {
|
||||||
|
return get('/emoticon/system')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置用户表情包服务接口
|
||||||
|
export const ServeSetUserEmoticon = data => {
|
||||||
|
return post('/emoticon/set-user-emoticon', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除收藏表情包服务接口
|
||||||
|
export const ServeDelCollectEmoticon = data => {
|
||||||
|
return post('/emoticon/del-collect-emoticon', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传表情包服务接口
|
||||||
|
export const ServeUploadEmoticon = data => {
|
||||||
|
return upload('/emoticon/upload-emoticon', data)
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { post, get, upload, del } from "@/utils/request";
|
||||||
|
|
||||||
|
export const ServeGetGoodsDetail = (data) => {
|
||||||
|
return get(`/im/goods/goods/sku/${data.goodsId}/${data.skuId}`);
|
||||||
|
};
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { post, get } from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询用户群聊服务接口
|
||||||
|
export const ServeGetGroups = () => {
|
||||||
|
return get('/group/list')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取群信息服务接口
|
||||||
|
export const ServeGroupDetail = data => {
|
||||||
|
return get('/group/detail', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建群聊服务接口
|
||||||
|
export const ServeCreateGroup = data => {
|
||||||
|
return post('/group/create', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改群信息
|
||||||
|
export const ServeEditGroup = data => {
|
||||||
|
return post('/group/edit', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 邀请好友加入群聊服务接口
|
||||||
|
export const ServeInviteGroup = data => {
|
||||||
|
return post('/group/invite', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除群聊成员服务接口
|
||||||
|
export const ServeRemoveMembersGroup = data => {
|
||||||
|
return post('/group/remove-members', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理员解散群聊服务接口
|
||||||
|
export const ServeDismissGroup = data => {
|
||||||
|
return post('/group/dismiss', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户退出群聊服务接口
|
||||||
|
export const ServeSecedeGroup = data => {
|
||||||
|
return post('/group/secede', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改群聊名片服务接口
|
||||||
|
export const ServeUpdateGroupCard = data => {
|
||||||
|
return post('/group/set-group-card', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户可邀请加入群组的好友列表
|
||||||
|
export const ServeGetInviteFriends = data => {
|
||||||
|
return get('/group/invite-friends', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取群组成员列表
|
||||||
|
export const ServeGetGroupMembers = data => {
|
||||||
|
return get('/group/members', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取群组公告列表
|
||||||
|
export const ServeGetGroupNotices = data => {
|
||||||
|
return get('/group/notices', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑群公告
|
||||||
|
export const ServeEditGroupNotice = data => {
|
||||||
|
return post('/group/edit-notice', data)
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { post, get, upload } from '@/utils/request'
|
||||||
|
|
||||||
|
// 上传头像裁剪图片服务接口
|
||||||
|
export const ServeUploadFileStream = data => {
|
||||||
|
return post('/upload/file-stream', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询大文件拆分信息服务接口
|
||||||
|
export const ServeFindFileSplitInfo = (data = {}) => {
|
||||||
|
return get('/upload/get-file-split-info', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件拆分上传服务接口
|
||||||
|
export const ServeFileSubareaUpload = (data = {}, options = {}) => {
|
||||||
|
return upload('/upload/file-subarea-upload', data, options)
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { get } from "@/utils/request";
|
||||||
|
|
||||||
|
// 获取用户相关设置信息
|
||||||
|
export const ServeGetUserSetting = () => {
|
||||||
|
return get("/im/user");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取店铺相关设置信息
|
||||||
|
export const ServeGetStoreSetting = () => {
|
||||||
|
return get("/im/user/store");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取用户相关设置信息
|
||||||
|
export const ServeGetUserDetail = (memberId) => {
|
||||||
|
return get(`/im/user/${memberId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取店铺相关设置信息
|
||||||
|
export const ServeGetStoreDetail = (storeId) => {
|
||||||
|
return get(`/im/user/store/${storeId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取店铺相关设置信息
|
||||||
|
export const ServeGetFootPrint = (params) => {
|
||||||
|
return get(`/im/user/history`,params);
|
||||||
|
};
|
||||||
|
// 获取订单列表信息
|
||||||
|
export const ServeGetOrderPrint = (params) => {
|
||||||
|
return get(`/im/orders/orders`,params);
|
||||||
|
};
|
|
@ -0,0 +1,238 @@
|
||||||
|
@import './reset.css';
|
||||||
|
|
||||||
|
.no-select {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-padding {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-box {
|
||||||
|
height: 35px;
|
||||||
|
width: 35px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: #508afe;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: white;
|
||||||
|
user-select: none;
|
||||||
|
transition: ease 1s;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-mask {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(22, 25, 29, 0.6);
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
color: white;
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .top-mask {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-border {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-radius0 {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-height {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.talk-height {
|
||||||
|
height: 80%;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ov-hidden {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动条样式
|
||||||
|
.lum-scrollbar {
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 3px;
|
||||||
|
background-color: #e4e4e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: #c0bebc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.larkc-tag {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 6px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: default;
|
||||||
|
user-select: none;
|
||||||
|
background-color: #dee0e3;
|
||||||
|
transform: scale(0.83);
|
||||||
|
transform-origin: left;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-center {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义 dialog 样式
|
||||||
|
// lum-dialog -- start
|
||||||
|
.lum-dialog-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 999;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: @maskBagColor;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.lum-dialog-box {
|
||||||
|
min-width: 200px;
|
||||||
|
min-height: 200px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 3px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 8px 0 rgba(31, 35, 41, 0.2);
|
||||||
|
margin: 0 10px;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #f5eeee;
|
||||||
|
|
||||||
|
>p:first-child {
|
||||||
|
text-indent: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
height: 100%;
|
||||||
|
width: 100px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-right: 20px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
/deep/.el-input__inner {
|
||||||
|
border-radius: 1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
border-radius: 2px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lum-dialog -- end
|
||||||
|
|
||||||
|
.talk-notify {
|
||||||
|
.el-notification__title {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
max-height: 65px;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
text-indent: -7px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.im-notify {
|
||||||
|
padding: 14px 26px 8px 0px;
|
||||||
|
|
||||||
|
.el-notification__closeBtn {
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification__group {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-2 {
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-8 {
|
||||||
|
flex: 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-4 {
|
||||||
|
flex: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-10 {
|
||||||
|
flex: 10;
|
||||||
|
}
|
|
@ -0,0 +1,991 @@
|
||||||
|
.markdown-body .octicon {
|
||||||
|
display: inline-block;
|
||||||
|
fill: currentColor;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .anchor {
|
||||||
|
float: left;
|
||||||
|
line-height: 1;
|
||||||
|
margin-left: -20px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .anchor:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 .octicon-link,
|
||||||
|
.markdown-body h2 .octicon-link,
|
||||||
|
.markdown-body h3 .octicon-link,
|
||||||
|
.markdown-body h4 .octicon-link,
|
||||||
|
.markdown-body h5 .octicon-link,
|
||||||
|
.markdown-body h6 .octicon-link {
|
||||||
|
color: #1b1f23;
|
||||||
|
vertical-align: middle;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1:hover .anchor,
|
||||||
|
.markdown-body h2:hover .anchor,
|
||||||
|
.markdown-body h3:hover .anchor,
|
||||||
|
.markdown-body h4:hover .anchor,
|
||||||
|
.markdown-body h5:hover .anchor,
|
||||||
|
.markdown-body h6:hover .anchor {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h2:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h3:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h4:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h5:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h6:hover .anchor .octicon-link {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1:hover .anchor .octicon-link:before,
|
||||||
|
.markdown-body h2:hover .anchor .octicon-link:before,
|
||||||
|
.markdown-body h3:hover .anchor .octicon-link:before,
|
||||||
|
.markdown-body h4:hover .anchor .octicon-link:before,
|
||||||
|
.markdown-body h5:hover .anchor .octicon-link:before,
|
||||||
|
.markdown-body h6:hover .anchor .octicon-link:before {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
content: ' ';
|
||||||
|
display: inline-block;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z'%3E%3C/path%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body {
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
font-family: Content-font, Roboto, sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #3B454E;
|
||||||
|
line-height: 1.625;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body details {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a {
|
||||||
|
background-color: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:active,
|
||||||
|
.markdown-body a:hover {
|
||||||
|
outline-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body strong {
|
||||||
|
font-weight: inherit;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: .67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code,
|
||||||
|
.markdown-body kbd,
|
||||||
|
.markdown-body pre {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
box-sizing: initial;
|
||||||
|
height: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
font: inherit;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body [type=checkbox] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a {
|
||||||
|
color: #0366d6;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body strong {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
height: 0;
|
||||||
|
margin: 15px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid #dfe2e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr:after,
|
||||||
|
.markdown-body hr:before {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table {
|
||||||
|
border-spacing: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body td,
|
||||||
|
.markdown-body th {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body details summary {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body kbd {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font: 11px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||||
|
line-height: 10px;
|
||||||
|
color: #444d56;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #fafbfc;
|
||||||
|
border: 1px solid #d1d5da;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: inset 0 -1px 0 #d1d5da;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1,
|
||||||
|
.markdown-body h2,
|
||||||
|
.markdown-body h3,
|
||||||
|
.markdown-body h4,
|
||||||
|
.markdown-body h5,
|
||||||
|
.markdown-body h6 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1,
|
||||||
|
.markdown-body h2 {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3,
|
||||||
|
.markdown-body h4 {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5,
|
||||||
|
.markdown-body h6 {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h6 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote {
|
||||||
|
margin: 20px 0 !important;
|
||||||
|
background-color: #f5f8fc;
|
||||||
|
padding: 1rem;
|
||||||
|
color: #8796a8;
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ol,
|
||||||
|
.markdown-body ul {
|
||||||
|
padding-left: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ol ol,
|
||||||
|
.markdown-body ul ol {
|
||||||
|
list-style-type: lower-roman;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ol ol ol,
|
||||||
|
.markdown-body ol ul ol,
|
||||||
|
.markdown-body ul ol ol,
|
||||||
|
.markdown-body ul ul ol {
|
||||||
|
list-style-type: lower-alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dd {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code,
|
||||||
|
.markdown-body pre {
|
||||||
|
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input::-webkit-inner-spin-button,
|
||||||
|
.markdown-body input::-webkit-outer-spin-button {
|
||||||
|
margin: 0;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :checked+.radio-label {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
border-color: #0366d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .border {
|
||||||
|
border: 1px solid #e1e4e8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .border-0 {
|
||||||
|
border: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .border-bottom {
|
||||||
|
border-bottom: 1px solid #e1e4e8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .rounded-1 {
|
||||||
|
border-radius: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .bg-white {
|
||||||
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .bg-gray-light {
|
||||||
|
background-color: #fafbfc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .text-gray-light {
|
||||||
|
color: #6a737d !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .mb-0 {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .my-2 {
|
||||||
|
margin-top: 8px !important;
|
||||||
|
margin-bottom: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-0 {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .py-0 {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-1 {
|
||||||
|
padding-left: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-2 {
|
||||||
|
padding-left: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .py-2 {
|
||||||
|
padding-top: 8px !important;
|
||||||
|
padding-bottom: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-3,
|
||||||
|
.markdown-body .px-3 {
|
||||||
|
padding-left: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .px-3 {
|
||||||
|
padding-right: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-4 {
|
||||||
|
padding-left: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-5 {
|
||||||
|
padding-left: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-6 {
|
||||||
|
padding-left: 40px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .f6 {
|
||||||
|
font-size: 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .lh-condensed {
|
||||||
|
line-height: 1.25 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .text-bold {
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-c {
|
||||||
|
color: #6a737d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-c1,
|
||||||
|
.markdown-body .pl-s .pl-v {
|
||||||
|
color: #005cc5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-e,
|
||||||
|
.markdown-body .pl-en {
|
||||||
|
color: #6f42c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-s .pl-s1,
|
||||||
|
.markdown-body .pl-smi {
|
||||||
|
color: #24292e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ent {
|
||||||
|
color: #22863a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-k {
|
||||||
|
color: #d73a49;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-pds,
|
||||||
|
.markdown-body .pl-s,
|
||||||
|
.markdown-body .pl-s .pl-pse .pl-s1,
|
||||||
|
.markdown-body .pl-sr,
|
||||||
|
.markdown-body .pl-sr .pl-cce,
|
||||||
|
.markdown-body .pl-sr .pl-sra,
|
||||||
|
.markdown-body .pl-sr .pl-sre {
|
||||||
|
color: #032f62;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-smw,
|
||||||
|
.markdown-body .pl-v {
|
||||||
|
color: #e36209;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-bu {
|
||||||
|
color: #b31d28;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ii {
|
||||||
|
color: #fafbfc;
|
||||||
|
background-color: #b31d28;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-c2 {
|
||||||
|
color: #fafbfc;
|
||||||
|
background-color: #d73a49;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-c2:before {
|
||||||
|
content: "^M";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-sr .pl-cce {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #22863a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ml {
|
||||||
|
color: #735c0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mh,
|
||||||
|
.markdown-body .pl-mh .pl-en,
|
||||||
|
.markdown-body .pl-ms {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #005cc5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mi {
|
||||||
|
font-style: italic;
|
||||||
|
color: #24292e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mb {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #24292e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-md {
|
||||||
|
color: #b31d28;
|
||||||
|
background-color: #ffeef0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mi1 {
|
||||||
|
color: #22863a;
|
||||||
|
background-color: #f0fff4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mc {
|
||||||
|
color: #e36209;
|
||||||
|
background-color: #ffebda;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mi2 {
|
||||||
|
color: #f6f8fa;
|
||||||
|
background-color: #005cc5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mdr {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #6f42c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ba {
|
||||||
|
color: #586069;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-sg {
|
||||||
|
color: #959da5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-corl {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #032f62;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .mb-0 {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .my-2 {
|
||||||
|
margin-bottom: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .my-2 {
|
||||||
|
margin-top: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-0 {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .py-0 {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-1 {
|
||||||
|
padding-left: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-2 {
|
||||||
|
padding-left: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .py-2 {
|
||||||
|
padding-top: 8px !important;
|
||||||
|
padding-bottom: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-3 {
|
||||||
|
padding-left: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-4 {
|
||||||
|
padding-left: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-5 {
|
||||||
|
padding-left: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-6 {
|
||||||
|
padding-left: 40px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-7 {
|
||||||
|
padding-left: 48px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-8 {
|
||||||
|
padding-left: 64px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-9 {
|
||||||
|
padding-left: 80px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-10 {
|
||||||
|
padding-left: 96px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-11 {
|
||||||
|
padding-left: 112px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-12 {
|
||||||
|
padding-left: 128px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
border-bottom-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body kbd {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font: 11px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||||
|
line-height: 10px;
|
||||||
|
color: #444d56;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #fafbfc;
|
||||||
|
border: 1px solid #d1d5da;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: inset 0 -1px 0 #d1d5da;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body:after,
|
||||||
|
.markdown-body:before {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body>:first-child {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body>:last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:not([href]) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote,
|
||||||
|
.markdown-body details,
|
||||||
|
.markdown-body dl,
|
||||||
|
.markdown-body ol,
|
||||||
|
.markdown-body p,
|
||||||
|
.markdown-body pre,
|
||||||
|
.markdown-body table,
|
||||||
|
.markdown-body ul {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
height: .25em;
|
||||||
|
padding: 0;
|
||||||
|
margin: 24px 0;
|
||||||
|
background-color: #e1e4e8;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote {
|
||||||
|
margin: 20px 0 !important;
|
||||||
|
background-color: #f5f8fc;
|
||||||
|
padding: 1rem;
|
||||||
|
color: #8796a8;
|
||||||
|
border-left: 3px solid #03A9F4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote>:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote>:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1,
|
||||||
|
.markdown-body h2,
|
||||||
|
.markdown-body h3,
|
||||||
|
.markdown-body h4,
|
||||||
|
.markdown-body h5,
|
||||||
|
.markdown-body h6 {
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1,
|
||||||
|
.markdown-body h2 {
|
||||||
|
padding-bottom: .3em;
|
||||||
|
/* border-bottom: 1px solid #eaecef; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5 {
|
||||||
|
font-size: .875em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h6 {
|
||||||
|
font-size: .85em;
|
||||||
|
color: #6a737d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ol,
|
||||||
|
.markdown-body ul {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ol ol,
|
||||||
|
.markdown-body ol ul,
|
||||||
|
.markdown-body ul ol,
|
||||||
|
.markdown-body ul ul {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body li {
|
||||||
|
word-wrap: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body li>p {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body li+li {
|
||||||
|
margin-top: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl dt {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 1em;
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl dd {
|
||||||
|
padding: 0 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table th {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table td,
|
||||||
|
.markdown-body table th {
|
||||||
|
padding: 6px 13px;
|
||||||
|
border: 1px solid #dfe2e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table tr {
|
||||||
|
background-color: #fff;
|
||||||
|
border-top: 1px solid #c6cbd1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table tr:nth-child(2n) {
|
||||||
|
background-color: #f6f8fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body img {
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: initial;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body img[align=right] {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body img[align=left] {
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code {
|
||||||
|
padding: .2em .4em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 85%;
|
||||||
|
background-color: rgba(27, 31, 35, .05);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
word-wrap: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre>code {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
word-break: normal;
|
||||||
|
white-space: pre;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight pre {
|
||||||
|
margin-bottom: 0;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight pre,
|
||||||
|
.markdown-body pre {
|
||||||
|
padding: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
font-size: 85%;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre code {
|
||||||
|
display: inline;
|
||||||
|
max-width: auto;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible;
|
||||||
|
line-height: inherit;
|
||||||
|
word-wrap: normal;
|
||||||
|
background-color: initial;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .commit-tease-sha {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||||
|
font-size: 90%;
|
||||||
|
color: #444d56;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .full-commit .btn-outline:not(:disabled):hover {
|
||||||
|
color: #005cc5;
|
||||||
|
border-color: #005cc5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .blob-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .blob-wrapper-embedded {
|
||||||
|
max-height: 240px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .blob-num {
|
||||||
|
width: 1%;
|
||||||
|
min-width: 50px;
|
||||||
|
padding-right: 10px;
|
||||||
|
padding-left: 10px;
|
||||||
|
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
color: rgba(27, 31, 35, .3);
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: top;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .blob-num:hover {
|
||||||
|
color: rgba(27, 31, 35, .6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .blob-num:before {
|
||||||
|
content: attr(data-line-number);
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .blob-code {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 10px;
|
||||||
|
padding-left: 10px;
|
||||||
|
line-height: 20px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .blob-code-inner {
|
||||||
|
overflow: visible;
|
||||||
|
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #24292e;
|
||||||
|
word-wrap: normal;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-token.active,
|
||||||
|
.markdown-body .pl-token:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background: #ffea7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="1"] {
|
||||||
|
-moz-tab-size: 1;
|
||||||
|
tab-size: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="2"] {
|
||||||
|
-moz-tab-size: 2;
|
||||||
|
tab-size: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="3"] {
|
||||||
|
-moz-tab-size: 3;
|
||||||
|
tab-size: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="4"] {
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="5"] {
|
||||||
|
-moz-tab-size: 5;
|
||||||
|
tab-size: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="6"] {
|
||||||
|
-moz-tab-size: 6;
|
||||||
|
tab-size: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="7"] {
|
||||||
|
-moz-tab-size: 7;
|
||||||
|
tab-size: 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="8"] {
|
||||||
|
-moz-tab-size: 8;
|
||||||
|
tab-size: 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="9"] {
|
||||||
|
-moz-tab-size: 9;
|
||||||
|
tab-size: 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="10"] {
|
||||||
|
-moz-tab-size: 10;
|
||||||
|
tab-size: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="11"] {
|
||||||
|
-moz-tab-size: 11;
|
||||||
|
tab-size: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .tab-size[data-tab-size="12"] {
|
||||||
|
-moz-tab-size: 12;
|
||||||
|
tab-size: 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item+.task-list-item {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item input {
|
||||||
|
margin: 0 .2em .25em -1.6em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
|
@ -0,0 +1,281 @@
|
||||||
|
.aside-box {
|
||||||
|
position: relative;
|
||||||
|
background-color: white;
|
||||||
|
border-right: 1px solid rgb(245, 245, 245);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 15px;
|
||||||
|
|
||||||
|
.from {
|
||||||
|
flex: 1 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
/deep/.el-input .el-input__inner {
|
||||||
|
border-radius: 20px;
|
||||||
|
width: 170px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
flex-basis: 32px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 32px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.tools-menu {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 38px;
|
||||||
|
width: 100px;
|
||||||
|
min-height: 80px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: rgba(31, 35, 41, 0.9);
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 1;
|
||||||
|
padding: 3px 0;
|
||||||
|
|
||||||
|
.menu1-item {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
color: white;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(70, 72, 73, 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右侧面板
|
||||||
|
.panel {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
&.border{
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.subheader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
border-top: 1px solid rgb(92, 156, 230);
|
||||||
|
border-bottom: 1px solid rgb(92, 156, 230);
|
||||||
|
|
||||||
|
p {
|
||||||
|
padding: 0 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: #508afe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-body {
|
||||||
|
overflow: auto;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.preloading {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 20px;
|
||||||
|
color: #afacac;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
height: 60px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px 15px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-bottom: 1px solid #f1ebeb;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
height: 35px;
|
||||||
|
width: 35px;
|
||||||
|
flex-basis: 35px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: #508afe;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: white;
|
||||||
|
user-select: none;
|
||||||
|
transition: ease 1s;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1;
|
||||||
|
margin-left: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
width: 100%;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
margin-right: 15px;
|
||||||
|
color: #1f2329;
|
||||||
|
}
|
||||||
|
|
||||||
|
.larkc-tag {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 6px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: default;
|
||||||
|
user-select: none;
|
||||||
|
background-color: #dee0e3;
|
||||||
|
transform: scale(0.8);
|
||||||
|
transform-origin: left;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wait {
|
||||||
|
background: #ffb445;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agree {
|
||||||
|
background: #53bd53;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 18px;
|
||||||
|
color: #8f959e;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 3px;
|
||||||
|
font-weight: 300;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.apply-from {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
right: -110px;
|
||||||
|
top: 0px;
|
||||||
|
height: 60px;
|
||||||
|
width: 100px;
|
||||||
|
transition: ease 0.5s 0.3s;
|
||||||
|
background-color: white;
|
||||||
|
opacity: 0;
|
||||||
|
button {
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 8px 4px #f1f1f1;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.apply-from {
|
||||||
|
opacity: 1;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.broadside-box {
|
||||||
|
position: absolute;
|
||||||
|
width: 350px;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
|
animation: showBox 0.5s ease-in-out;
|
||||||
|
-webkit-animation: showBox 0.5s ease-in-out;
|
||||||
|
-moz-animation: showBox 0.5s ease-in-out;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0 14px #cccccc70;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes showBox {
|
||||||
|
0% {
|
||||||
|
transform: translateX(350px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes showBox {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(350px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
-webkit-transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
/deep/.el-input__inner {
|
||||||
|
border-radius: 1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#auth-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f6f8fb;
|
||||||
|
|
||||||
|
#logo-name {
|
||||||
|
width: 200px;
|
||||||
|
height: 38px;
|
||||||
|
font-size: 34px;
|
||||||
|
font-family: Times New Roman, Georgia, Serif;
|
||||||
|
color: #2196f3;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login-box {
|
||||||
|
position: absolute;
|
||||||
|
width: 350px;
|
||||||
|
min-height: 480px;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 0 #ccc;
|
||||||
|
box-shadow: 0 4px 14px 0 rgba(206, 207, 209, 0.5);
|
||||||
|
padding: 10px 20px;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
width: 100%;
|
||||||
|
height: 38px;
|
||||||
|
font-size: 22px;
|
||||||
|
margin: 25px 0 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.links {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: normal !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-code-btn {
|
||||||
|
width: 140px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
display: inline-block;
|
||||||
|
background: #f3ecec;
|
||||||
|
text-align: center;
|
||||||
|
color: #777373;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: #e4dbdb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-sms-disable {
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
background: #f7f7f7 !important;
|
||||||
|
color: silver !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-account {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
height: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
color: rgb(45, 44, 44);
|
||||||
|
font-weight: 100;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 70%;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #b1a0a0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #777272;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-height: 500px) {
|
||||||
|
.copyright {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fly-box {
|
||||||
|
.fly {
|
||||||
|
pointer-events: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-fly-circle1 {
|
||||||
|
left: 40px;
|
||||||
|
top: 100px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
rgba(100, 84, 239, 0.07) 0%,
|
||||||
|
rgba(48, 33, 236, 0.04) 100%
|
||||||
|
);
|
||||||
|
animation: move 2.5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-fly-circle2 {
|
||||||
|
left: 3%;
|
||||||
|
top: 60%;
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
rgba(100, 84, 239, 0.08) 0%,
|
||||||
|
rgba(48, 33, 236, 0.04) 100%
|
||||||
|
);
|
||||||
|
animation: move 3s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-fly-circle3 {
|
||||||
|
right: 2%;
|
||||||
|
top: 140px;
|
||||||
|
width: 145px;
|
||||||
|
height: 145px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
rgba(100, 84, 239, 0.1) 0%,
|
||||||
|
rgba(48, 33, 236, 0.04) 100%
|
||||||
|
);
|
||||||
|
animation: move 2.5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-fly-circle4 {
|
||||||
|
right: 5%;
|
||||||
|
top: 60%;
|
||||||
|
width: 160px;
|
||||||
|
height: 160px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
rgba(100, 84, 239, 0.02) 0%,
|
||||||
|
rgba(48, 33, 236, 0.04) 100%
|
||||||
|
);
|
||||||
|
animation: move 3.5s linear infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes move {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translateY(25px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body,
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
min-width: 500px;
|
||||||
|
font-family: "Microsoft YaHei";
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-size: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
img {
|
||||||
|
-webkit-touch-callout: none
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: none;
|
||||||
|
outline: 0;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
border: none;
|
||||||
|
background: #fff;
|
||||||
|
font-family: "Microsoft YaHei";
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearfix {
|
||||||
|
clear: both;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
overflow: hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear {
|
||||||
|
clear: both;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
.message-group {
|
||||||
|
min-height: 30px;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 3px 12px 3px 0;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-box {
|
||||||
|
width: 50px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
user-select: none;
|
||||||
|
padding-top: 8px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-box {
|
||||||
|
flex: auto;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 0px 5px 15px 5px;
|
||||||
|
|
||||||
|
.msg-header {
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #a09a9a;
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/.text-message {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
//主题皮肤 - 预留功能
|
||||||
|
:root {
|
||||||
|
--themeBagColor: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------- 定义 Less 变量 -------
|
||||||
|
@themeBagColor: var(--themeBagColor);
|
||||||
|
|
||||||
|
// 遮罩层背景颜色
|
||||||
|
@maskBagColor: rgba(31, 35, 41, .3);
|
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 830 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 789 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 671 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 151 KiB |
After Width: | Height: | Size: 192 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 758 B |
After Width: | Height: | Size: 882 B |
After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,313 @@
|
||||||
|
<template>
|
||||||
|
<div class="lum-dialog-mask">
|
||||||
|
<div class="container animated bounceInDown" :class="{ 'full-screen': isFullScreen }">
|
||||||
|
<el-container class="full-height">
|
||||||
|
<el-header class="header no-padding" height="50px">
|
||||||
|
<div class="tools">
|
||||||
|
<span>选择编程语言: </span>
|
||||||
|
<el-select v-model="language" size="mini" filterable placeholder="语言类型" :disabled="!editMode">
|
||||||
|
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<i class="el-icon-close close-btn" @click="close" />
|
||||||
|
<i class="iconfont icon-full-screen" :class="{
|
||||||
|
'icon-tuichuquanping': isFullScreen,
|
||||||
|
'icon-quanping ': !isFullScreen,
|
||||||
|
}" :title="isFullScreen ? '关闭全屏模式' : '打开全屏模式'" @click="isFullScreen = !isFullScreen" />
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-main class="main no-padding">
|
||||||
|
<PrismEditor class="peditor" style="border-radius: 0" :code="code" :language="language" :line-numbers="true"
|
||||||
|
@change="codeChanged" />
|
||||||
|
</el-main>
|
||||||
|
|
||||||
|
<el-footer class="footer no-padding" height="50px">
|
||||||
|
<div class="code-num">
|
||||||
|
<span>代码字数:{{ code.length }}字</span>
|
||||||
|
<span v-show="code.length > 10000 && editMode" class="code-warning">
|
||||||
|
(字数不能超过10000字)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttom-group">
|
||||||
|
<el-button size="small" plain @click="close">
|
||||||
|
{{ editMode ? '取消编辑' : '关闭预览' }}
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button v-show="editMode" type="primary" size="small" @click="submit">发送代码
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-footer>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import PrismEditor from "vue-prism-editor";
|
||||||
|
import "vue-prism-editor/dist/VuePrismEditor.css";
|
||||||
|
import "prismjs/themes/prism-okaidia.css";
|
||||||
|
import Vue from "vue";
|
||||||
|
import { Select, Option } from "element-ui";
|
||||||
|
Vue.use(Select);
|
||||||
|
Vue.use(Option);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TalkCodeBlock",
|
||||||
|
components: {
|
||||||
|
PrismEditor,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
loadCode: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
loadLang: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
editMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
language: "",
|
||||||
|
code: "",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: "css",
|
||||||
|
label: "css",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "less",
|
||||||
|
label: "less",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "javascript",
|
||||||
|
label: "javascript",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "json",
|
||||||
|
label: "json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "bash",
|
||||||
|
label: "bash",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "c",
|
||||||
|
label: "c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "cil",
|
||||||
|
label: "cil",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "docker",
|
||||||
|
label: "docker",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "git",
|
||||||
|
label: "git",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "go",
|
||||||
|
label: "go",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "java",
|
||||||
|
label: "java",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "lua",
|
||||||
|
label: "lua",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "nginx",
|
||||||
|
label: "nginx",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "objectivec",
|
||||||
|
label: "objectivec",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "php",
|
||||||
|
label: "php",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "python",
|
||||||
|
label: "python",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "ruby",
|
||||||
|
label: "ruby",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "rust",
|
||||||
|
label: "rust",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "sql",
|
||||||
|
label: "sql",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "swift",
|
||||||
|
label: "swift",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "vim",
|
||||||
|
label: "vim",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "visual-basic",
|
||||||
|
label: "visual-basic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "shell",
|
||||||
|
label: "shell",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isFullScreen: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
loadCode(value) {
|
||||||
|
this.code = value;
|
||||||
|
},
|
||||||
|
loadLang(value) {
|
||||||
|
this.language = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.code = this.loadCode;
|
||||||
|
this.language = this.loadLang;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit() {
|
||||||
|
if (!this.code) {
|
||||||
|
this.$message.error("代码块不能为空...");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.language == "") {
|
||||||
|
this.$message.error("请选择语言");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.code.length > 10000) {
|
||||||
|
this.$message.error("代码字数不能超过10000字!!!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.$emit("confirm", {
|
||||||
|
language: this.language,
|
||||||
|
code: this.code,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.$emit("close");
|
||||||
|
},
|
||||||
|
codeChanged(code) {
|
||||||
|
this.code = code;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.container {
|
||||||
|
width: 80%;
|
||||||
|
max-width: 800px;
|
||||||
|
height: 600px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 8px 0 rgba(31, 35, 41, 0.2);
|
||||||
|
transition: 0.5s ease;
|
||||||
|
background: #2d2d2d;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
position: relative;
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 12px;
|
||||||
|
top: 13px;
|
||||||
|
font-size: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-full-screen {
|
||||||
|
position: absolute;
|
||||||
|
right: 45px;
|
||||||
|
top: 13px;
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
line-height: 50px;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
background-color: #3c3c3c;
|
||||||
|
padding-right: 20px;
|
||||||
|
line-height: 50px;
|
||||||
|
|
||||||
|
.code-num {
|
||||||
|
float: left;
|
||||||
|
color: white;
|
||||||
|
padding-left: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-warning {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttom-group {
|
||||||
|
float: right;
|
||||||
|
height: 100%;
|
||||||
|
line-height: 50px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-screen {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-input__inner {
|
||||||
|
border-radius: 0;
|
||||||
|
width: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ pre {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .prism-editor-wrapper pre::-webkit-scrollbar {
|
||||||
|
background-color: #272822;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .prism-editor-wrapper pre::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #41413f;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .prism-editor-wrapper::-webkit-scrollbar {
|
||||||
|
background-color: #272822;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .prism-editor-wrapper::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgb(114, 112, 112);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,139 @@
|
||||||
|
<template>
|
||||||
|
<div class="lum-dialog-mask" v-show="isShow">
|
||||||
|
<el-container class="lum-dialog-box" v-outside="close">
|
||||||
|
<el-header class="no-padding header" height="60px">
|
||||||
|
<p>会话记录 ({{ records.length }})</p>
|
||||||
|
<p class="tools">
|
||||||
|
<i class="el-icon-close" @click="close" />
|
||||||
|
</p>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="no-padding main" v-loading="loading">
|
||||||
|
<el-scrollbar class="full-height" tag="section" :native="false">
|
||||||
|
<div v-for="record in records" :key="record.id" class="message-group">
|
||||||
|
<div class="left-box">
|
||||||
|
<el-avatar
|
||||||
|
fit="contain"
|
||||||
|
shape="square"
|
||||||
|
:size="30"
|
||||||
|
:src="record.avatar"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right-box">
|
||||||
|
<div class="msg-header">
|
||||||
|
<span class="name">
|
||||||
|
{{
|
||||||
|
record.nickname_remarks
|
||||||
|
? record.nickname_remarks
|
||||||
|
: record.nickname
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<span class="time">{{ record.created_at }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文本消息 -->
|
||||||
|
<text-message
|
||||||
|
v-if="record.msg_type == 1"
|
||||||
|
:content="record.content"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件 - 图片消息 -->
|
||||||
|
<image-message
|
||||||
|
v-else-if="record.msg_type == 2 && record.file.file_type == 1"
|
||||||
|
:src="record.file.file_url"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件 - 音频消息 -->
|
||||||
|
<audio-message
|
||||||
|
v-else-if="record.msg_type == 2 && record.file.file_type == 2"
|
||||||
|
:src="record.file.file_url"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件 - 视频消息 -->
|
||||||
|
<video-message
|
||||||
|
v-else-if="record.msg_type == 2 && record.file.file_type == 3"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件 - 其它格式文件 -->
|
||||||
|
<file-message
|
||||||
|
v-else-if="record.msg_type == 2 && record.file.file_type == 4"
|
||||||
|
:file="record.file"
|
||||||
|
:record_id="record.id"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 代码块消息 -->
|
||||||
|
<code-message
|
||||||
|
v-else-if="record.msg_type == 4"
|
||||||
|
:code="record.code_block.code"
|
||||||
|
:lang="record.code_block.code_lang"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div v-else class="other-message">未知消息类型</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { ServeGetForwardRecords } from '@/api/chat'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TalkForwardRecord',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
record_id: 0,
|
||||||
|
records: [],
|
||||||
|
loading: false,
|
||||||
|
isShow: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(record_id) {
|
||||||
|
if (record_id !== this.record_id) {
|
||||||
|
this.record_id = record_id
|
||||||
|
this.records = []
|
||||||
|
this.loadRecords()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isShow = true
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.isShow = false
|
||||||
|
},
|
||||||
|
loadRecords() {
|
||||||
|
this.loading = true
|
||||||
|
ServeGetForwardRecords({
|
||||||
|
record_id: this.record_id,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.records = res.data.rows
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.lum-dialog-mask {
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lum-dialog-box {
|
||||||
|
width: 500px;
|
||||||
|
max-width: 500px;
|
||||||
|
height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/.el-scrollbar__wrap {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@import '~@/assets/css/talk/talk-records.less';
|
||||||
|
</style>
|
|
@ -0,0 +1,602 @@
|
||||||
|
<template>
|
||||||
|
<div class="lum-dialog-mask">
|
||||||
|
<el-container class="lum-dialog-box" :class="{ 'full-screen': fullscreen }">
|
||||||
|
<el-header height="60px" class="header">
|
||||||
|
<p>消息管理器</p>
|
||||||
|
<p class="title">
|
||||||
|
<span>{{ query.talk_type == 1 ? "好友" : "群" }}【{{ title }}】</span>
|
||||||
|
</p>
|
||||||
|
<p class="tools">
|
||||||
|
<i
|
||||||
|
class="iconfont"
|
||||||
|
style="transform: scale(0.85)"
|
||||||
|
:class="fullscreen ? 'icon-tuichuquanping' : 'icon-quanping'"
|
||||||
|
@click="fullscreen = !fullscreen"
|
||||||
|
/>
|
||||||
|
<i class="el-icon-close" @click="$emit('close')" />
|
||||||
|
</p>
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-header height="38px" class="sub-header">
|
||||||
|
<i
|
||||||
|
class="iconfont pointer"
|
||||||
|
:class="{ 'icon-shouqi2': broadside, 'icon-zhankai': !broadside }"
|
||||||
|
@click="triggerBroadside"
|
||||||
|
/>
|
||||||
|
<div class="search-box no-select">
|
||||||
|
<i class="el-icon-search" />
|
||||||
|
<input
|
||||||
|
v-model="search.keyword"
|
||||||
|
type="text"
|
||||||
|
maxlength="30"
|
||||||
|
placeholder="关键字搜索"
|
||||||
|
@keyup.enter="searchText($event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-container class="full-height ov-hidden">
|
||||||
|
<el-aside width="200px" class="broadside" v-show="broadside">
|
||||||
|
<el-container class="full-height">
|
||||||
|
<el-header height="40px" class="aside-header">
|
||||||
|
<div
|
||||||
|
class="item"
|
||||||
|
:class="{ selected: contacts.show == 'friends' }"
|
||||||
|
@click="contacts.show = 'friends'"
|
||||||
|
>
|
||||||
|
我的好友({{ contacts.friends.length }})
|
||||||
|
</div>
|
||||||
|
<div class="item-shuxian">|</div>
|
||||||
|
<div
|
||||||
|
class="item"
|
||||||
|
:class="{ selected: contacts.show == 'groups' }"
|
||||||
|
@click="contacts.show = 'groups'"
|
||||||
|
>
|
||||||
|
我的群组({{ contacts.groups.length }})
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="no-padding">
|
||||||
|
<el-scrollbar class="full-height" tag="section" :native="false">
|
||||||
|
<div
|
||||||
|
v-for="item in contacts[contacts.show]"
|
||||||
|
class="contacts-item pointer"
|
||||||
|
:class="{
|
||||||
|
selected:
|
||||||
|
query.talk_type == item.type &&
|
||||||
|
query.receiver_id == item.id,
|
||||||
|
}"
|
||||||
|
:key="item.id"
|
||||||
|
@click="triggerMenuItem(item)"
|
||||||
|
>
|
||||||
|
<div class="avatar">
|
||||||
|
<el-avatar :size="20" :src="item.avatar">
|
||||||
|
<img src="~@/assets/image/detault-avatar.jpg" />
|
||||||
|
</el-avatar>
|
||||||
|
</div>
|
||||||
|
<div class="content" v-text="item.name"></div>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</el-aside>
|
||||||
|
|
||||||
|
<!-- 聊天记录阅览 -->
|
||||||
|
<el-main v-show="showBox == 0" class="no-padding">
|
||||||
|
<el-container class="full-height">
|
||||||
|
<el-header height="40px" class="type-items">
|
||||||
|
<span
|
||||||
|
v-for="tab in tabType"
|
||||||
|
:class="{ active: query.msg_type == tab.type }"
|
||||||
|
@click="triggerLoadType(tab.type)"
|
||||||
|
>{{ tab.name }}
|
||||||
|
</span>
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-main
|
||||||
|
v-if="records.isEmpty"
|
||||||
|
class="history-record animated fadeIn"
|
||||||
|
>
|
||||||
|
<div class="empty-records">
|
||||||
|
<img src="~@/assets/image/chat-search-no-message.png" />
|
||||||
|
<p>暂无聊天记录</p>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
|
||||||
|
<el-main v-else class="history-record">
|
||||||
|
<el-scrollbar class="full-height" tag="section" :native="false">
|
||||||
|
<div
|
||||||
|
v-for="record in records.items"
|
||||||
|
:key="record.id"
|
||||||
|
class="message-group"
|
||||||
|
>
|
||||||
|
<div class="left-box">
|
||||||
|
<el-avatar
|
||||||
|
shape="square"
|
||||||
|
fit="contain"
|
||||||
|
:size="30"
|
||||||
|
:src="record.avatar"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right-box">
|
||||||
|
<div class="msg-header">
|
||||||
|
<span class="name">
|
||||||
|
{{
|
||||||
|
record.nickname_remarks
|
||||||
|
? record.nickname_remarks
|
||||||
|
: record.nickname
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<span class="time">{{ record.created_at }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文本消息 -->
|
||||||
|
<text-message
|
||||||
|
v-if="record.msg_type == 1"
|
||||||
|
:content="record.content"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件 - 图片消息 -->
|
||||||
|
<image-message
|
||||||
|
v-else-if="
|
||||||
|
record.msg_type == 2 && record.file.file_type == 1
|
||||||
|
"
|
||||||
|
:src="record.file.file_url"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件 - 音频消息 -->
|
||||||
|
<audio-message
|
||||||
|
v-else-if="
|
||||||
|
record.msg_type == 2 && record.file.file_type == 2
|
||||||
|
"
|
||||||
|
:src="record.file.file_url"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件 - 视频消息 -->
|
||||||
|
<video-message
|
||||||
|
v-else-if="
|
||||||
|
record.msg_type == 2 && record.file.file_type == 3
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件 - 其它格式文件 -->
|
||||||
|
<file-message
|
||||||
|
v-else-if="
|
||||||
|
record.msg_type == 2 && record.file.file_type == 4
|
||||||
|
"
|
||||||
|
:file="record.file"
|
||||||
|
:record_id="record.id"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 会话记录消息 -->
|
||||||
|
<forward-message
|
||||||
|
v-else-if="record.msg_type == 3"
|
||||||
|
:forward="record.forward"
|
||||||
|
:record_id="record.id"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 代码块消息 -->
|
||||||
|
<code-message
|
||||||
|
v-else-if="record.msg_type == 4"
|
||||||
|
:code="record.code_block.code"
|
||||||
|
:lang="record.code_block.code_lang"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 投票消息 -->
|
||||||
|
<vote-message
|
||||||
|
v-else-if="record.msg_type == 5"
|
||||||
|
:record_id="record.id"
|
||||||
|
:vote="record.vote"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div v-else class="other-message">未知消息类型</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据加载栏 -->
|
||||||
|
<div v-show="records.loadStatus == 1" class="load-button blue">
|
||||||
|
<i class="el-icon-loading" />
|
||||||
|
<span>加载数据中...</span>
|
||||||
|
</div>
|
||||||
|
<div v-show="records.loadStatus == 0" class="load-button">
|
||||||
|
<i class="el-icon-arrow-down" />
|
||||||
|
<span @click="loadChatRecord">加载更多...</span>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { ServeGetContacts } from "@/api/contacts";
|
||||||
|
import { ServeFindTalkRecords } from "@/api/chat";
|
||||||
|
import { formatSize as renderSize, download, imgZoom } from "@/utils/functions";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TalkSearchRecord",
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
talk_type: 0,
|
||||||
|
receiver_id: 0,
|
||||||
|
title: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fullscreen: false,
|
||||||
|
|
||||||
|
user_id: this.$store.state.user.id,
|
||||||
|
title: "",
|
||||||
|
|
||||||
|
// 侧边栏相关信息
|
||||||
|
broadside: false,
|
||||||
|
contacts: {
|
||||||
|
show: "friends",
|
||||||
|
friends: [],
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
|
||||||
|
query: {
|
||||||
|
talk_type: 0,
|
||||||
|
receiver_id: 0,
|
||||||
|
msg_type: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 用户聊天记录
|
||||||
|
records: {
|
||||||
|
record_id: 0,
|
||||||
|
items: [],
|
||||||
|
isEmpty: false,
|
||||||
|
loadStatus: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
showBox: 0,
|
||||||
|
|
||||||
|
tabType: [
|
||||||
|
{ name: "全部", type: 0 },
|
||||||
|
{ name: "文件", type: 2 },
|
||||||
|
{ name: "会话记录", type: 3 },
|
||||||
|
{ name: "代码块", type: 4 },
|
||||||
|
{ name: "群投票", type: 5 },
|
||||||
|
],
|
||||||
|
|
||||||
|
search: {
|
||||||
|
keyword: "", // 关键字查询
|
||||||
|
date: "", // 时间查询
|
||||||
|
page: 1, // 当前分页
|
||||||
|
totalPage: 50, // 总分页
|
||||||
|
items: [], // 数据列表
|
||||||
|
isShowDate: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.title = this.params.title;
|
||||||
|
this.query = {
|
||||||
|
talk_type: this.params.talk_type,
|
||||||
|
receiver_id: this.params.receiver_id,
|
||||||
|
msg_type: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadChatRecord(0);
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadFriends();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
download,
|
||||||
|
renderSize,
|
||||||
|
|
||||||
|
// 获取图片信息
|
||||||
|
getImgStyle(url) {
|
||||||
|
return imgZoom(url, 200);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取会话记录消息名称
|
||||||
|
getForwardTitle(item) {
|
||||||
|
let arr = [...new Set(item.map((v) => v.nickname))];
|
||||||
|
return arr.join("、") + "的会话记录";
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取好友列表
|
||||||
|
loadFriends() {
|
||||||
|
ServeGetContacts().then(({ code, data }) => {
|
||||||
|
if (code == 200) {
|
||||||
|
this.contacts.friends = data.map((item) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
type: 1,
|
||||||
|
avatar: item.avatar,
|
||||||
|
name: item.friend_remark ? item.friend_remark : item.nickname,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 左侧联系人菜单点击事件
|
||||||
|
triggerMenuItem(item) {
|
||||||
|
this.title = item.name;
|
||||||
|
this.query.talk_type = item.type;
|
||||||
|
this.query.receiver_id = item.id;
|
||||||
|
this.showBox = 0;
|
||||||
|
|
||||||
|
this.triggerLoadType(0);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载历史记录
|
||||||
|
loadChatRecord() {
|
||||||
|
let data = {
|
||||||
|
talk_type: this.query.talk_type,
|
||||||
|
receiver_id: this.query.receiver_id,
|
||||||
|
record_id: this.records.record_id,
|
||||||
|
msg_type: this.query.msg_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.records.loadStatus == 1) return;
|
||||||
|
|
||||||
|
this.records.loadStatus = 1;
|
||||||
|
ServeFindTalkRecords(data)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code != 200) return;
|
||||||
|
|
||||||
|
let records = data.record_id == 0 ? [] : this.records.items;
|
||||||
|
|
||||||
|
records.push(...res.data.rows);
|
||||||
|
|
||||||
|
this.records.items = records;
|
||||||
|
this.records.loadStatus =
|
||||||
|
res.data.rows.length < res.data.limit ? 2 : 0;
|
||||||
|
|
||||||
|
if (this.records.items.length == 0) {
|
||||||
|
this.records.isEmpty = true;
|
||||||
|
} else {
|
||||||
|
this.records.record_id =
|
||||||
|
this.records.items[this.records.items.length - 1].id;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.records.loadStatus = 0;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
triggerLoadType(type) {
|
||||||
|
this.records.record_id = 0;
|
||||||
|
this.query.msg_type = type;
|
||||||
|
this.records.isEmpty = false;
|
||||||
|
this.records.items = [];
|
||||||
|
|
||||||
|
this.loadChatRecord();
|
||||||
|
},
|
||||||
|
|
||||||
|
searchText() {
|
||||||
|
if (this.search.keyword == "") {
|
||||||
|
this.showBox = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$notify.info({
|
||||||
|
title: "消息",
|
||||||
|
message: "查询功能正在开发中...",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
triggerBroadside() {
|
||||||
|
this.broadside = !this.broadside;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
/deep/.el-scrollbar__wrap {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lum-dialog-mask {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lum-dialog-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 600px;
|
||||||
|
max-width: 800px;
|
||||||
|
transition: 1s ease;
|
||||||
|
|
||||||
|
&.full-screen {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-width: unset;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-header {
|
||||||
|
height: 38px;
|
||||||
|
line-height: 38px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #f9f4f4;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 0 10px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 22px;
|
||||||
|
color: #6f6a6a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
position: absolute;
|
||||||
|
width: 230px;
|
||||||
|
height: 32px;
|
||||||
|
top: 2px;
|
||||||
|
right: 10px;
|
||||||
|
background: #f9f4f4;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
position: absolute;
|
||||||
|
left: 35px;
|
||||||
|
top: 3px;
|
||||||
|
height: 25px;
|
||||||
|
width: 184px;
|
||||||
|
color: #7d7171;
|
||||||
|
background: #f9f4f4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.broadside {
|
||||||
|
@border: 1px solid #f9f9f9;
|
||||||
|
border-right: @border;
|
||||||
|
user-select: none;
|
||||||
|
transition: 3s ease;
|
||||||
|
|
||||||
|
.aside-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
height: 100%;
|
||||||
|
border-bottom: @border;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
flex: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
color: #66b1ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-shuxian {
|
||||||
|
flex-basis: 1px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: rgb(232 224 224);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contacts-item {
|
||||||
|
height: 35px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding-left: 10px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
flex-basis: 40px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1 1;
|
||||||
|
height: 100%;
|
||||||
|
line-height: 35px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 13px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.selected {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first box */
|
||||||
|
.type-items {
|
||||||
|
padding: 0 0 0 10px;
|
||||||
|
line-height: 40px;
|
||||||
|
user-select: none;
|
||||||
|
border-bottom: 1px solid #f9f4f4;
|
||||||
|
|
||||||
|
.active {
|
||||||
|
color: #03a9f4;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
height: 40px;
|
||||||
|
width: 45px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-record {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-button {
|
||||||
|
width: 100%;
|
||||||
|
height: 35px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
&.blue {
|
||||||
|
color: #51b2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-left: 5px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-records {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
color: #cccccc;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "~@/assets/css/talk/talk-records.less";
|
||||||
|
</style>
|
|
@ -0,0 +1,193 @@
|
||||||
|
<template>
|
||||||
|
<div class="audio-message">
|
||||||
|
<div class="videodisc">
|
||||||
|
<div class="disc" :class="{ play: isPlay }" @click="toPlay">
|
||||||
|
<i v-if="loading" class="el-icon-loading" />
|
||||||
|
<i v-else-if="isPlay" class="el-icon-video-pause" />
|
||||||
|
<i v-else class="el-icon-video-play" />
|
||||||
|
<audio
|
||||||
|
ref="audio"
|
||||||
|
type="audio/mp3"
|
||||||
|
:src="src"
|
||||||
|
@timeupdate="timeupdate"
|
||||||
|
@ended="ended"
|
||||||
|
@canplay="canplay"
|
||||||
|
></audio>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="detail">
|
||||||
|
<div class="text">
|
||||||
|
<i class="el-icon-service" />
|
||||||
|
<span>{{ getCurrDuration }} / {{ getTotalDuration }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="process">
|
||||||
|
<el-progress :percentage="progress" :show-text="false" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function formatSeconds(value) {
|
||||||
|
var theTime = parseInt(value) // 秒
|
||||||
|
var theTime1 = 0 // 分
|
||||||
|
var theTime2 = 0 // 小时
|
||||||
|
if (theTime > 60) {
|
||||||
|
theTime1 = parseInt(theTime / 60)
|
||||||
|
theTime = parseInt(theTime % 60)
|
||||||
|
if (theTime1 > 60) {
|
||||||
|
theTime2 = parseInt(theTime1 / 60)
|
||||||
|
theTime1 = parseInt(theTime1 % 60)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = '' + parseInt(theTime) //秒
|
||||||
|
if (10 > theTime > 0) {
|
||||||
|
result = '0' + parseInt(theTime) //秒
|
||||||
|
} else {
|
||||||
|
result = '' + parseInt(theTime) //秒
|
||||||
|
}
|
||||||
|
|
||||||
|
if (10 > theTime1 > 0) {
|
||||||
|
result = '0' + parseInt(theTime1) + ':' + result //分,不足两位数,首位补充0,
|
||||||
|
} else {
|
||||||
|
result = '' + parseInt(theTime1) + ':' + result //分
|
||||||
|
}
|
||||||
|
if (theTime2 > 0) {
|
||||||
|
result = '' + parseInt(theTime2) + ':' + result //时
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AudioMessage',
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
isPlay: false,
|
||||||
|
duration: 0,
|
||||||
|
currentTime: 0,
|
||||||
|
progress: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
getTotalDuration() {
|
||||||
|
return formatSeconds(this.duration)
|
||||||
|
},
|
||||||
|
getCurrDuration() {
|
||||||
|
return formatSeconds(this.currentTime)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toPlay() {
|
||||||
|
if (this.loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let audio = this.$refs.audio
|
||||||
|
if (this.isPlay) {
|
||||||
|
audio.pause()
|
||||||
|
} else {
|
||||||
|
audio.play()
|
||||||
|
}
|
||||||
|
this.isPlay = !this.isPlay
|
||||||
|
},
|
||||||
|
|
||||||
|
// 当目前的播放位置已更改时
|
||||||
|
timeupdate() {
|
||||||
|
let audio = this.$refs.audio
|
||||||
|
this.currentTime = audio.currentTime
|
||||||
|
this.progress = (audio.currentTime / audio.duration) * 100
|
||||||
|
},
|
||||||
|
|
||||||
|
// 当浏览器可以播放音频/视频时
|
||||||
|
canplay() {
|
||||||
|
this.duration = this.$refs.audio.duration
|
||||||
|
this.loading = false
|
||||||
|
},
|
||||||
|
|
||||||
|
// 当目前的播放列表已结束时
|
||||||
|
ended() {
|
||||||
|
this.isPlay = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.audio-message {
|
||||||
|
width: 200px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid #03a9f4;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videodisc {
|
||||||
|
flex-basis: 60px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.disc {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
background: #e9e5e5;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: ease 0.5;
|
||||||
|
|
||||||
|
&.play {
|
||||||
|
background: #ff5722;
|
||||||
|
box-shadow: 0 0 4px 0px #f76a3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active i {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail {
|
||||||
|
flex: 1 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
width: 90%;
|
||||||
|
font-size: 12px;
|
||||||
|
i {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.process {
|
||||||
|
padding-top: 10px;
|
||||||
|
height: 20px;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,148 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="code-message"
|
||||||
|
:class="{
|
||||||
|
'max-height': lineNumber > 6,
|
||||||
|
'max-width': maxwidth,
|
||||||
|
'full-screen': fullscreen,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
:class="
|
||||||
|
fullscreen ? 'el-icon-close' : 'iconfont icon-tubiao_chakangongyi'
|
||||||
|
"
|
||||||
|
@click="fullscreen = !fullscreen"
|
||||||
|
/>
|
||||||
|
<pre class="lum-scrollbar" v-html="formatCode(code, lang)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Prism from 'prismjs'
|
||||||
|
import 'prismjs/themes/prism-okaidia.css'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CodeMessage',
|
||||||
|
props: {
|
||||||
|
code: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
lang: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
maxwidth: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fullscreen: false,
|
||||||
|
lineNumber: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.lineNumber = this.code.split(/\n/).length
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatCode(code, lang) {
|
||||||
|
try {
|
||||||
|
return Prism.highlight(code, Prism.languages[lang], lang) + '<br/>'
|
||||||
|
} catch (error) {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.code-message {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&.max-width {
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.max-height {
|
||||||
|
height: 208px;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
top: 0px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: white;
|
||||||
|
display: inline-block;
|
||||||
|
opacity: 0;
|
||||||
|
width: 50px;
|
||||||
|
height: 30px;
|
||||||
|
background: #171616;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 30px;
|
||||||
|
border-radius: 0 0 0px 8px;
|
||||||
|
transition: 1s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
i {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px;
|
||||||
|
line-height: 24px;
|
||||||
|
background: #272822;
|
||||||
|
color: #d5d4d4;
|
||||||
|
font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
|
||||||
|
'Courier New', monospace;
|
||||||
|
font-size: 85%;
|
||||||
|
|
||||||
|
&.lum-scrollbar {
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.full-screen {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
max-width: unset;
|
||||||
|
max-height: unset;
|
||||||
|
border-radius: 0px;
|
||||||
|
background: #272822;
|
||||||
|
z-index: 99999999;
|
||||||
|
|
||||||
|
i {
|
||||||
|
position: fixed;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: 24px;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
box-shadow: 0 0 5px 0px #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,145 @@
|
||||||
|
<template>
|
||||||
|
<div class="file-message">
|
||||||
|
<div class="main">
|
||||||
|
<div class="ext">{{ ext }}</div>
|
||||||
|
<div class="file-box">
|
||||||
|
<p class="info">
|
||||||
|
<span class="name">{{ fileName }}</span>
|
||||||
|
<span class="size">({{ fileSize }})</span>
|
||||||
|
</p>
|
||||||
|
<p class="notice">文件已成功发送, 文件助手永久保存</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<a @click="download(record_id)">下载</a>
|
||||||
|
<a>在线预览</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { formatSize, download } from '@/utils/functions'
|
||||||
|
export default {
|
||||||
|
name: 'FileMessage',
|
||||||
|
props: {
|
||||||
|
file: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
record_id: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
file_id: 0,
|
||||||
|
ext: '',
|
||||||
|
fileName: '',
|
||||||
|
fileSize: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.file_id = this.file.id
|
||||||
|
this.ext = this.file.file_suffix.toUpperCase()
|
||||||
|
this.fileName = this.file.original_name
|
||||||
|
this.fileSize = formatSize(this.file.file_size)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
download,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.file-message {
|
||||||
|
width: 250px;
|
||||||
|
height: 85px;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0 5px 0px #e8e4e4;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: all 0.5s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 5px 0px #cac6c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
height: 45px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.ext {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: #ffffff;
|
||||||
|
background: #49a4ff;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-box {
|
||||||
|
flex: 1 1;
|
||||||
|
height: 45px;
|
||||||
|
margin-left: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 24px;
|
||||||
|
color: rgb(76, 76, 76);
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
flex: 1 auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #cac6c6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice {
|
||||||
|
height: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #929191;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
height: 30px;
|
||||||
|
line-height: 37px;
|
||||||
|
color: #409eff;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 12px;
|
||||||
|
border-top: 1px solid #eff7ef;
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin: 0 3px;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: royalblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,116 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="forward-message" @click="catForwardRecords">
|
||||||
|
<div class="title">{{ title }}</div>
|
||||||
|
<div v-for="(record, index) in records" :key="index" class="lists">
|
||||||
|
<p>
|
||||||
|
<span>{{ record.nickname }}:</span>
|
||||||
|
<span>{{ record.text }}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<span>转发:聊天会话记录 ({{ num }}条)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 会话记录查看器 -->
|
||||||
|
<talk-forward-record ref="forwardRecordsRef" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import TalkForwardRecord from '@/components/chat/TalkForwardRecord'
|
||||||
|
export default {
|
||||||
|
name: 'ForwardMessage',
|
||||||
|
components: {
|
||||||
|
TalkForwardRecord,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
forward: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
record_id: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
title: '',
|
||||||
|
records: [],
|
||||||
|
num: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
catForwardRecords() {
|
||||||
|
this.$refs.forwardRecordsRef.open(this.record_id)
|
||||||
|
},
|
||||||
|
getForwardTitle(list) {
|
||||||
|
let arr = [...new Set(list.map(v => v.nickname))]
|
||||||
|
return arr.join('、') + '的会话记录'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
let forward = this.forward
|
||||||
|
|
||||||
|
this.num = forward.num
|
||||||
|
this.records = forward.list
|
||||||
|
this.title = this.getForwardTitle(this.records)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
/* 会话记录消息 */
|
||||||
|
.forward-message {
|
||||||
|
width: 250px;
|
||||||
|
min-height: 95px;
|
||||||
|
max-height: 150px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: white;
|
||||||
|
padding: 3px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 0 5px 0px #e8e4e4;
|
||||||
|
text-align: left;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #565353;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lists p {
|
||||||
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #aaa9a9;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
height: 32px;
|
||||||
|
line-height: 35px;
|
||||||
|
color: #858282;
|
||||||
|
border-top: 1px solid #f1ebeb;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 12px;
|
||||||
|
font-weight: 300;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 5px 0px #cac6c6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,150 @@
|
||||||
|
<template>
|
||||||
|
<!-- 好友申请消息 -->
|
||||||
|
<div class="apply-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<img class="avatar" :src="avatar" />
|
||||||
|
<div class="nickname">No. {{ nickname }}</div>
|
||||||
|
<div class="datetime">{{ datetime }}</div>
|
||||||
|
<div class="remarks">
|
||||||
|
<span>备注信息:{{ remarks }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="mini-button" @click="handle(1)">同意</div>
|
||||||
|
<el-divider direction="vertical"></el-divider>
|
||||||
|
<div class="mini-button" @click="handle(2)">拒绝</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'FriendApplyMessage',
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
avatar:
|
||||||
|
'http://im-img.gzydong.club/media/images/avatar/20210602/60b6f03598ed0104301.png',
|
||||||
|
nickname: '独特态度',
|
||||||
|
datetime: '05/09 12:13 分',
|
||||||
|
remarks: '编辑个签,展示我的独特态度 展示我的独特态度。',
|
||||||
|
apply_id: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
methods: {
|
||||||
|
handle(type) {
|
||||||
|
alert(type)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.apply-card {
|
||||||
|
position: relative;
|
||||||
|
width: 170px;
|
||||||
|
min-height: 180px;
|
||||||
|
border-radius: 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.5s;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-image: linear-gradient(-84deg, #1ab6ff 0, #1ab6ff 0, #82c1f3 100%);
|
||||||
|
// #028fff
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 135px;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
position: absolute;
|
||||||
|
top: 18px;
|
||||||
|
left: 8px;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 8px;
|
||||||
|
width: 90px;
|
||||||
|
height: 25px;
|
||||||
|
font-size: 10px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 25px;
|
||||||
|
color: white;
|
||||||
|
border-bottom: 1px dashed white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.datetime {
|
||||||
|
position: absolute;
|
||||||
|
top: 42px;
|
||||||
|
right: 11.5px;
|
||||||
|
color: white;
|
||||||
|
font-size: 10px;
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.remarks {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
color: white;
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
overflow: hidden;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
border-top: 1px solid white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
/deep/.el-divider {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-button {
|
||||||
|
display: flex;
|
||||||
|
width: 50px;
|
||||||
|
height: 25px;
|
||||||
|
margin: 0 10px;
|
||||||
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<div class="image-message no-select">
|
||||||
|
<el-image
|
||||||
|
fit="cover"
|
||||||
|
:src="src"
|
||||||
|
:lazy="true"
|
||||||
|
:style="getImgStyle(src)"
|
||||||
|
:preview-src-list="[src]"
|
||||||
|
>
|
||||||
|
<div slot="error" class="image-slot">图片加载失败...</div>
|
||||||
|
<div slot="placeholder" class="image-slot">图片加载中...</div>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { imgZoom } from '@/utils/functions'
|
||||||
|
export default {
|
||||||
|
name: 'ImageMessage',
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getImgStyle(url) {
|
||||||
|
return imgZoom(url, 200)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.image-message {
|
||||||
|
/deep/.el-image {
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #f1efef;
|
||||||
|
|
||||||
|
.image-slot {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #908686;
|
||||||
|
background: #efeaea;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<div class="invite-message">
|
||||||
|
<div v-if="invite.type == 1 || invite.type == 3" class="system-msg">
|
||||||
|
<a @click="toUser(invite.operate_user.id)">
|
||||||
|
{{ invite.operate_user.nickname }}
|
||||||
|
</a>
|
||||||
|
<span>{{ invite.type == 1 ? '邀请了' : '将' }}</span>
|
||||||
|
<template v-for="(user, uidx) in invite.users">
|
||||||
|
<a @click="toUser(user.id)">{{ user.nickname }}</a>
|
||||||
|
<em v-show="uidx < invite.users.length - 1">、</em>
|
||||||
|
</template>
|
||||||
|
<span>{{ invite.type == 1 ? '加入了群聊' : '踢出了群聊' }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="invite.type == 2" class="system-msg">
|
||||||
|
<a @click="toUser(invite.operate_user.id)">
|
||||||
|
{{ invite.operate_user.nickname }}
|
||||||
|
</a>
|
||||||
|
<span>退出了群聊</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'InviteMessage',
|
||||||
|
props: {
|
||||||
|
invite: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toUser(user_id) {
|
||||||
|
this.$emit('cat', user_id)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.invite-message {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-msg {
|
||||||
|
margin: 10px auto;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 8px;
|
||||||
|
word-break: break-all;
|
||||||
|
word-wrap: break-word;
|
||||||
|
color: #979191;
|
||||||
|
user-select: none;
|
||||||
|
font-weight: 300;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #939596;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,101 @@
|
||||||
|
<template>
|
||||||
|
<!-- 登录消息 -->
|
||||||
|
<div class="login-message">
|
||||||
|
<h4>登录操作通知</h4>
|
||||||
|
<p>登录时间:{{ datetime }} (CST)</p>
|
||||||
|
<p>IP地址:{{ ip }}</p>
|
||||||
|
<p>登录地点:{{ address }}</p>
|
||||||
|
<p>登录设备:{{ platform }}</p>
|
||||||
|
<p>异常原因:{{ reason }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { parseTime } from '@/utils/functions'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LoginMessage',
|
||||||
|
props: {
|
||||||
|
detail: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
datetime: '',
|
||||||
|
ip: '',
|
||||||
|
address: '',
|
||||||
|
platform: '',
|
||||||
|
reason: '常用设备登录',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.ip = this.detail.ip
|
||||||
|
this.datetime = parseTime(
|
||||||
|
this.detail.created_at,
|
||||||
|
'{y}年{m}月{d}日 {h}:{i}:{s}'
|
||||||
|
)
|
||||||
|
this.address = this.detail.address
|
||||||
|
this.reason = this.detail.reason
|
||||||
|
|
||||||
|
this.platform =
|
||||||
|
this.getExploreName(this.detail.agent) +
|
||||||
|
' / ' +
|
||||||
|
this.getExploreOs(this.detail.agent)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getExploreName(userAgent = '') {
|
||||||
|
if (userAgent.indexOf('Opera') > -1 || userAgent.indexOf('OPR') > -1) {
|
||||||
|
return 'Opera'
|
||||||
|
} else if (
|
||||||
|
userAgent.indexOf('compatible') > -1 &&
|
||||||
|
userAgent.indexOf('MSIE') > -1
|
||||||
|
) {
|
||||||
|
return 'IE'
|
||||||
|
} else if (userAgent.indexOf('Edge') > -1) {
|
||||||
|
return 'Edge'
|
||||||
|
} else if (userAgent.indexOf('Firefox') > -1) {
|
||||||
|
return 'Firefox'
|
||||||
|
} else if (
|
||||||
|
userAgent.indexOf('Safari') > -1 &&
|
||||||
|
userAgent.indexOf('Chrome') == -1
|
||||||
|
) {
|
||||||
|
return 'Safari'
|
||||||
|
} else if (
|
||||||
|
userAgent.indexOf('Chrome') > -1 &&
|
||||||
|
userAgent.indexOf('Safari') > -1
|
||||||
|
) {
|
||||||
|
return 'Chrome'
|
||||||
|
} else {
|
||||||
|
return 'Unkonwn'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getExploreOs(userAgent = '') {
|
||||||
|
if (userAgent.indexOf('Mac OS') > -1) {
|
||||||
|
return 'Mac OS'
|
||||||
|
} else {
|
||||||
|
return 'Windows'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.login-message {
|
||||||
|
width: 300px;
|
||||||
|
min-height: 50px;
|
||||||
|
background: #f7f7f7;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 10px 0;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<template>
|
||||||
|
<div class="reply-message">这是回复的消息[预留]</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ReplyMessage',
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.reply-message {
|
||||||
|
margin-top: 5px;
|
||||||
|
min-height: 28px;
|
||||||
|
background: #f7f1f1;
|
||||||
|
line-height: 28px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #a7a2a2;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,66 @@
|
||||||
|
<template>
|
||||||
|
<div class="revoke-message">
|
||||||
|
<div class="content">
|
||||||
|
<span v-if="$store.state.user.id == item.user_id">
|
||||||
|
你撤回了一条消息 | {{ sendTime(item.created_at) }}
|
||||||
|
</span>
|
||||||
|
<span v-else-if="item.talk_type == 1">
|
||||||
|
对方撤回了一条消息 | {{ sendTime(item.created_at) }}
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
"{{ item.nickname }}" 撤回了一条消息 | {{ sendTime(item.created_at) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { formatTime as sendTime } from "@/utils/functions";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "RevokeMessage",
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
sendTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.revoke-message {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin: 10px auto;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 8px;
|
||||||
|
word-break: break-all;
|
||||||
|
word-wrap: break-word;
|
||||||
|
color: #979191;
|
||||||
|
user-select: none;
|
||||||
|
font-weight: 300;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #939596;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<template>
|
||||||
|
<div class="system-text-message">
|
||||||
|
<div class="content">{{ content }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { formatTime as sendTime } from '@/utils/functions'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SystemTextMessage',
|
||||||
|
props: {
|
||||||
|
content: String,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
sendTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.system-text-message {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin: 10px auto;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 8px;
|
||||||
|
word-break: break-all;
|
||||||
|
word-wrap: break-word;
|
||||||
|
color: #979191;
|
||||||
|
user-select: none;
|
||||||
|
font-weight: 300;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,109 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="text-message"
|
||||||
|
:class="{
|
||||||
|
left: float == 'left',
|
||||||
|
right: float == 'right',
|
||||||
|
'max-width': !fullWidth,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div v-if="arrow" class="arrow"></div>
|
||||||
|
<pre v-html="html" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { textReplaceLink } from "@/utils/functions";
|
||||||
|
import { textReplaceEmoji } from "@/utils/emojis";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TextMessage",
|
||||||
|
props: {
|
||||||
|
content: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
float: {
|
||||||
|
type: String,
|
||||||
|
default: "left",
|
||||||
|
},
|
||||||
|
fullWidth: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
arrow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
html: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
const text = textReplaceLink(
|
||||||
|
this.content,
|
||||||
|
this.float == "right" ? "#ffffff" : "rgb(9 149 208)"
|
||||||
|
);
|
||||||
|
|
||||||
|
this.html = textReplaceEmoji(text);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@bg-left-color: #f5f5f5;
|
||||||
|
@bg-right-color: #1ebafc;
|
||||||
|
|
||||||
|
.text-message {
|
||||||
|
position: relative;
|
||||||
|
min-width: 30px;
|
||||||
|
min-height: 30px;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
font-size: 0;
|
||||||
|
border: 5px solid;
|
||||||
|
top: 6px;
|
||||||
|
left: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.max-width {
|
||||||
|
max-width: calc(100% - 50px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
color: #3a3a3a;
|
||||||
|
background: @bg-left-color;
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
border-color: transparent @bg-left-color transparent transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.right {
|
||||||
|
color: #fff;
|
||||||
|
background: @bg-right-color;
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
right: -10px;
|
||||||
|
left: unset;
|
||||||
|
border-color: transparent transparent transparent @bg-right-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
font-size: 15px;
|
||||||
|
padding: 3px 10px;
|
||||||
|
font-family: "Microsoft YaHei";
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<template>
|
||||||
|
<!-- 用户卡片消息 - 预留 -->
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'UserCardMessage',
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
watch: {},
|
||||||
|
methods: {},
|
||||||
|
created() {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped></style>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<template>
|
||||||
|
<div class="video-message">
|
||||||
|
视频消息
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VideoMessage',
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
created() {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped></style>
|
|
@ -0,0 +1,134 @@
|
||||||
|
<template>
|
||||||
|
<div class="visit-card-message">
|
||||||
|
<div class="user flex-center">
|
||||||
|
<div class="avatar flex-center">
|
||||||
|
<el-avatar :size="28" :src="avatar" />
|
||||||
|
</div>
|
||||||
|
<div class="content flex-center">
|
||||||
|
<p class="ellipsis">{{ nickname }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="tools flex-center">
|
||||||
|
<span class="flex-center pointer">
|
||||||
|
<i class="el-icon-plus" /> 加好友
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sign"><span>个性签名 : </span>{{ sign }}</div>
|
||||||
|
<div class="share no-select ellipsis">
|
||||||
|
<a class="pointer" @click="openVisitCard(friendId)">你是谁?</a>
|
||||||
|
分享了用户名片,可点击添加好友 ...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VisitCardMessage',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userId: 0,
|
||||||
|
friendId: 0,
|
||||||
|
avatar:
|
||||||
|
'http://im-serve0.gzydong.club/static/image/sys-head/2019012107542668696.jpg',
|
||||||
|
sign:
|
||||||
|
'这个社会,是赢家通吃,输者一无所有,社会,永远都是只以成败论英雄。',
|
||||||
|
nickname:
|
||||||
|
'氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
methods: {
|
||||||
|
openVisitCard(user_id) {
|
||||||
|
this.$emit('openVisitCard', user_id)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.ellipsis {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visit-card-message {
|
||||||
|
min-height: 130px;
|
||||||
|
min-width: 100px;
|
||||||
|
max-width: 300px;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #ece5e5;
|
||||||
|
transition: all 0.5s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 8px #e2d3d3;
|
||||||
|
transform: scale(1.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user {
|
||||||
|
height: 40px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
> div {
|
||||||
|
height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
flex-basis: 30px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1 1;
|
||||||
|
margin: 0 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
flex-basis: 60px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
span {
|
||||||
|
width: 65px;
|
||||||
|
height: 30px;
|
||||||
|
background: #409eff;
|
||||||
|
color: white;
|
||||||
|
font-size: 13px;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 0 8px;
|
||||||
|
transform: scale(0.8);
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: #83b0f3;
|
||||||
|
transform: scale(0.83);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign {
|
||||||
|
min-height: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
background: #f3f5f7;
|
||||||
|
color: #7d7d7d;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 10px 0;
|
||||||
|
span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.share {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #7d7d7d;
|
||||||
|
a {
|
||||||
|
color: #4cabf7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<template>
|
||||||
|
<div class="voice-message"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VoiceMessage',
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
created() {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped></style>
|
|
@ -0,0 +1,299 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="vote-message">
|
||||||
|
<div class="vote-from">
|
||||||
|
<div class="vheader">
|
||||||
|
<p>
|
||||||
|
{{ answer_mode == 1 ? "[多选投票]" : "[单选投票]" }}
|
||||||
|
<i
|
||||||
|
v-show="is_vote"
|
||||||
|
class="pointer"
|
||||||
|
:class="{
|
||||||
|
'el-icon-loading': refresh,
|
||||||
|
'el-icon-refresh': !refresh,
|
||||||
|
}"
|
||||||
|
title="刷新投票结果"
|
||||||
|
@click="loadRefresh"
|
||||||
|
></i>
|
||||||
|
</p>
|
||||||
|
<p>{{ title }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-if="is_vote">
|
||||||
|
<div class="vbody">
|
||||||
|
<div class="vote-view" v-for="(option, index) in options">
|
||||||
|
<p class="vote-option">{{ option.value }}. {{ option.text }}</p>
|
||||||
|
<p class="vote-census">
|
||||||
|
{{ option.num }} 票 {{ option.progress }}%
|
||||||
|
</p>
|
||||||
|
<p class="vote-progress">
|
||||||
|
<el-progress
|
||||||
|
:show-text="false"
|
||||||
|
:percentage="parseInt(option.progress)"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="vfooter vote-view">
|
||||||
|
<p>应参与人数:{{ answer_num }} 人</p>
|
||||||
|
<p>实际参与人数:{{ answered_num }} 人</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="vbody">
|
||||||
|
<p class="option" v-for="(option, index) in options">
|
||||||
|
<el-checkbox
|
||||||
|
v-model="option.is_checked"
|
||||||
|
@change="toSelect2(option)"
|
||||||
|
/>
|
||||||
|
<span @click="toSelect(option, index)" style="margin-left: 10px">
|
||||||
|
{{ option.value }} 、{{ option.text }}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="vfooter">
|
||||||
|
<el-button plain round @click="toVote">
|
||||||
|
{{ isUserVote ? "立即投票" : "请选择进行投票" }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ServeConfirmVoteHandle } from "@/api/chat";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "VoteMessage",
|
||||||
|
props: {
|
||||||
|
vote: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
record_id: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
answer_mode: 0,
|
||||||
|
title: "啊谁叫你打开你卡沙发那,那就是看、卡收纳是你",
|
||||||
|
radio_value: "",
|
||||||
|
options: [],
|
||||||
|
is_vote: false,
|
||||||
|
answer_num: 0,
|
||||||
|
answered_num: 0,
|
||||||
|
refresh: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isUserVote() {
|
||||||
|
return this.options.some((iten) => {
|
||||||
|
return iten.is_checked;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
let user_id = this.$store.state.user.id;
|
||||||
|
let { detail, statistics, vote_users } = this.vote;
|
||||||
|
|
||||||
|
this.answer_mode = detail.answer_mode;
|
||||||
|
this.answer_num = detail.answer_num;
|
||||||
|
this.answered_num = detail.answered_num;
|
||||||
|
|
||||||
|
detail.answer_option.forEach((item) => {
|
||||||
|
this.options.push({
|
||||||
|
value: item.key,
|
||||||
|
text: item.value,
|
||||||
|
is_checked: false,
|
||||||
|
num: 0,
|
||||||
|
progress: "00.0",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.is_vote = vote_users.some((value) => {
|
||||||
|
return value == user_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.updateStatistics(statistics);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadRefresh() {
|
||||||
|
this.refresh = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.refresh = false;
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
updateStatistics(data) {
|
||||||
|
let count = data.count;
|
||||||
|
this.options.forEach((option) => {
|
||||||
|
option.num = data.options[option.value];
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
option.progress = (data.options[option.value] / count) * 100;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
toSelect(option, index) {
|
||||||
|
if (this.answer_mode == 0) {
|
||||||
|
this.options.forEach((option) => {
|
||||||
|
option.is_checked = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options[index].is_checked = !option.is_checked;
|
||||||
|
},
|
||||||
|
toSelect2(option) {
|
||||||
|
if (this.answer_mode == 0) {
|
||||||
|
this.options.forEach((item) => {
|
||||||
|
if (option.value == item.value) {
|
||||||
|
item.is_checked = option.is_checked;
|
||||||
|
} else {
|
||||||
|
item.is_checked = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toVote() {
|
||||||
|
if (this.isUserVote == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = [];
|
||||||
|
this.options.forEach((item) => {
|
||||||
|
if (item.is_checked) {
|
||||||
|
items.push(item.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ServeConfirmVoteHandle({
|
||||||
|
record_id: this.record_id,
|
||||||
|
options: items.join(","),
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.is_vote = true;
|
||||||
|
this.updateStatistics(res.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.vote-message {
|
||||||
|
width: 300px;
|
||||||
|
min-height: 150px;
|
||||||
|
border: 1px solid #eceff1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.vote-from {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.vheader {
|
||||||
|
min-height: 50px;
|
||||||
|
background: #4e83fd;
|
||||||
|
padding: 8px;
|
||||||
|
position: relative;
|
||||||
|
p {
|
||||||
|
margin: 3px 0;
|
||||||
|
&:first-child {
|
||||||
|
color: rgb(245, 237, 237);
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "投票";
|
||||||
|
position: absolute;
|
||||||
|
font-size: 60px;
|
||||||
|
color: white;
|
||||||
|
opacity: 0.1;
|
||||||
|
top: -5px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vbody {
|
||||||
|
min-height: 80px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 5px 15px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
.option {
|
||||||
|
margin: 14px 0px;
|
||||||
|
font-size: 13px;
|
||||||
|
span {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-radio {
|
||||||
|
margin-right: 0;
|
||||||
|
.el-radio__label {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vfooter {
|
||||||
|
height: 55px;
|
||||||
|
text-align: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width: 80%;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vote-view {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding-left: 15px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
border-left: 2px solid #2196f3;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-view {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 30px;
|
||||||
|
margin: 15px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
> p {
|
||||||
|
margin: 6px 0px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-option {
|
||||||
|
min-height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-census {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,33 @@
|
||||||
|
import AudioMessage from './AudioMessage.vue';
|
||||||
|
import CodeMessage from './CodeMessage.vue';
|
||||||
|
import ForwardMessage from './ForwardMessage.vue';
|
||||||
|
import ImageMessage from './ImageMessage.vue';
|
||||||
|
import TextMessage from './TextMessage.vue';
|
||||||
|
import VideoMessage from './VideoMessage.vue';
|
||||||
|
import VoiceMessage from './VoiceMessage.vue';
|
||||||
|
import SystemTextMessage from './SystemTextMessage.vue';
|
||||||
|
import FileMessage from './FileMessage.vue';
|
||||||
|
import InviteMessage from './InviteMessage.vue';
|
||||||
|
import RevokeMessage from './RevokeMessage.vue';
|
||||||
|
import VisitCardMessage from './VisitCardMessage.vue';
|
||||||
|
import ReplyMessage from './ReplyMessage.vue';
|
||||||
|
import VoteMessage from './VoteMessage.vue';
|
||||||
|
import LoginMessage from './LoginMessage.vue';
|
||||||
|
|
||||||
|
export {
|
||||||
|
AudioMessage,
|
||||||
|
CodeMessage,
|
||||||
|
ForwardMessage,
|
||||||
|
ImageMessage,
|
||||||
|
TextMessage,
|
||||||
|
VideoMessage,
|
||||||
|
VoiceMessage,
|
||||||
|
SystemTextMessage,
|
||||||
|
FileMessage,
|
||||||
|
InviteMessage,
|
||||||
|
RevokeMessage,
|
||||||
|
VisitCardMessage,
|
||||||
|
ReplyMessage,
|
||||||
|
VoteMessage,
|
||||||
|
LoginMessage
|
||||||
|
}
|
|
@ -0,0 +1,226 @@
|
||||||
|
<template>
|
||||||
|
<el-tabs v-model="activeName" @tab-click="handleClick" type="card" :stretch=true>
|
||||||
|
<el-tab-pane :label="toUser.storeFlag ? '正在咨询' : '他的足迹'" name="history">
|
||||||
|
<div style="margin-left: 12px;" v-if="toUser.storeFlag">
|
||||||
|
<GoodsLink :goodsDetail="goodsDetail" v-if="toUser.userId === goodsDetail.storeId"
|
||||||
|
@sendMessage="submitSendMessage" />
|
||||||
|
<FootPrint :list="footPrintList" @loadMore="loadMoreFootPrint()" :orderList="orderPrintList"
|
||||||
|
@sendMessage="submitSendMessage" />
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="店铺信息" name="UserInfo" v-if="toUser.storeFlag">
|
||||||
|
<div v-if="toUser.storeFlag">
|
||||||
|
<StoreDetail :storeInfo="storeInfo" />
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Tabs, TabPane } from 'element-ui'
|
||||||
|
import { ServeGetStoreDetail, ServeGetUserDetail, ServeGetFootPrint, ServeGetOrderPrint } from '@/api/user'
|
||||||
|
import { ServeGetGoodsDetail } from '@/api/goods'
|
||||||
|
import StoreDetail from "@/components/chat/panel/template/storeDetail.vue";
|
||||||
|
import FootPrint from "@/components/chat/panel/template/footPrint.vue";
|
||||||
|
import GoodsLink from "@/components/chat/panel/template/goodsLink.vue";
|
||||||
|
import SocketInstance from "@/im-server/socket-instance";
|
||||||
|
import { mapState, mapGetters } from "vuex";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
"el-tabs": Tabs,
|
||||||
|
"el-tab-pane": TabPane,
|
||||||
|
StoreDetail,
|
||||||
|
FootPrint,
|
||||||
|
GoodsLink
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
toUser: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
goodsParams: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(["talkItems"]),
|
||||||
|
...mapState({
|
||||||
|
index_name: (state) => state.dialogue.index_name,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
activeName: 'history',
|
||||||
|
storeInfo: {}, //店铺信息
|
||||||
|
memberInfo: {}, //会员信息
|
||||||
|
footPrintParams: {
|
||||||
|
pageSize: 10,
|
||||||
|
pageNumber: 1,
|
||||||
|
memberId: '',
|
||||||
|
storeId: '',
|
||||||
|
},
|
||||||
|
goodsDetail: {},
|
||||||
|
footPrintList: [], // 商品
|
||||||
|
orderPrintList: []// 订单
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if (this.toUser.storeFlag) {
|
||||||
|
this.getStoreDetail()
|
||||||
|
} else {
|
||||||
|
this.getMemberDetail()
|
||||||
|
}
|
||||||
|
this.getFootPrint()
|
||||||
|
if (this.goodsParams) {
|
||||||
|
this.getGoodsDetail()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getStoreDetail () {
|
||||||
|
ServeGetStoreDetail(this.toUser.userId).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
this.storeInfo = res.result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadMoreFootPrint (e) {
|
||||||
|
//触底再次调接口
|
||||||
|
this.footPrintParams.pageNumber++
|
||||||
|
this.getFootPrint()
|
||||||
|
},
|
||||||
|
handleClick () { },
|
||||||
|
getMemberDetail () {
|
||||||
|
ServeGetUserDetail(this.toUser.userId).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
this.memberInfo = res.result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getGoodsDetail () {
|
||||||
|
ServeGetGoodsDetail(this.goodsParams).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
this.goodsDetail = res.result.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getFootPrint () {
|
||||||
|
if (this.toUser.storeFlag) {
|
||||||
|
this.footPrintParams.memberId = this.id
|
||||||
|
this.footPrintParams.storeId = this.toUser.userId
|
||||||
|
} else {
|
||||||
|
this.footPrintParams.memberId = this.toUser.userId
|
||||||
|
this.footPrintParams.storeId = this.id
|
||||||
|
}
|
||||||
|
ServeGetFootPrint(this.footPrintParams).then(res => {
|
||||||
|
res.result.records.forEach((item, index) => {
|
||||||
|
if (localStorage.getItem(item.goodsId)) {
|
||||||
|
item.btnHide = 0
|
||||||
|
} else {
|
||||||
|
item.btnHide = 1
|
||||||
|
}
|
||||||
|
if (item.goodsId === this.goodsParams.goodsId) {
|
||||||
|
res.result.records.splice(index, 1)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.footPrintList.push(...res.result.records)
|
||||||
|
})
|
||||||
|
// 订单列表
|
||||||
|
ServeGetOrderPrint(this.footPrintParams).then((res) => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
res.result.records.forEach((item) => {
|
||||||
|
this.orderPrintList.push({
|
||||||
|
...item,
|
||||||
|
btnHide: 1
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// this.orderPrintList.push(...res.result.records)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 发送消息回调事件
|
||||||
|
submitSendMessage (record, context, messageType) {
|
||||||
|
SocketInstance.emit("event_talk", record);
|
||||||
|
this.$store.commit("UPDATE_TALK_ITEM", {
|
||||||
|
index_name: this.index_name,
|
||||||
|
draft_text: "",
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* 插入数据
|
||||||
|
*/
|
||||||
|
const insterChat = {
|
||||||
|
createTime: this.formateDateAndTimeToString(new Date()),
|
||||||
|
fromUser: this.id,
|
||||||
|
toUser: record.to,
|
||||||
|
isRead: false,
|
||||||
|
messageType: messageType,
|
||||||
|
text: context,
|
||||||
|
float: "right",
|
||||||
|
};
|
||||||
|
|
||||||
|
// 插入对话记录
|
||||||
|
this.$store.commit("PUSH_DIALOGUE", insterChat);
|
||||||
|
// 获取聊天面板元素节点
|
||||||
|
let el = document.getElementById("lumenChatPanel");
|
||||||
|
// 判断的滚动条是否在底部
|
||||||
|
let isBottom =
|
||||||
|
Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight;
|
||||||
|
|
||||||
|
if (isBottom || record.to == this.id) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
el.scrollTop = el.scrollHeight;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$store.commit("SET_TLAK_UNREAD_MESSAGE", {
|
||||||
|
content: content,
|
||||||
|
nickname: record.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
formateDateAndTimeToString (date) {
|
||||||
|
var hours = date.getHours();
|
||||||
|
var mins = date.getMinutes();
|
||||||
|
var secs = date.getSeconds();
|
||||||
|
var msecs = date.getMilliseconds();
|
||||||
|
if (hours < 10) hours = "0" + hours;
|
||||||
|
if (mins < 10) mins = "0" + mins;
|
||||||
|
if (secs < 10) secs = "0" + secs;
|
||||||
|
if (msecs < 10) secs = "0" + msecs;
|
||||||
|
return (
|
||||||
|
this.formatDateToString(date) + " " + hours + ":" + mins + ":" + secs
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
formatDateToString (date) {
|
||||||
|
var year = date.getFullYear();
|
||||||
|
var month = date.getMonth() + 1;
|
||||||
|
var day = date.getDate();
|
||||||
|
if (month < 10) month = "0" + month;
|
||||||
|
if (day < 10) day = "0" + day;
|
||||||
|
return year + "-" + month + "-" + day;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
// /deep/ .el-tabs__nav.is-top {
|
||||||
|
// }
|
||||||
|
|
||||||
|
/deep/ .el-tabs__nav {
|
||||||
|
height: 60px;
|
||||||
|
line-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-tab-pane {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,278 @@
|
||||||
|
<template>
|
||||||
|
<el-header id="panel-header">
|
||||||
|
<div class="module left-module">
|
||||||
|
<span
|
||||||
|
class="icon-badge"
|
||||||
|
v-show="params.is_robot == 0"
|
||||||
|
:class="{ 'red-color': params.talk_type == 1 }"
|
||||||
|
>
|
||||||
|
{{ params.talk_type == 1 ? '好友' : '群组' }}
|
||||||
|
</span>
|
||||||
|
<span class="nickname">{{ params.nickname }}</span>
|
||||||
|
<span v-show="params.talk_type == 2" class="num">({{ groupNum }})</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="params.talk_type == 1 && params.is_robot == 0" class="module center-module">
|
||||||
|
<p class="online">
|
||||||
|
<span v-show="isOnline" class="online-status"></span>
|
||||||
|
<span>{{ isOnline ? '在线' : '离线' }}</span>
|
||||||
|
</p>
|
||||||
|
<p class="keyboard-status" v-show="isKeyboard">对方正在输入 ...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="module right-module" >
|
||||||
|
<el-tooltip content="历史消息" placement="top">
|
||||||
|
<p v-show="params.is_robot == 0">
|
||||||
|
<i class="el-icon-time" @click="triggerEvent('history')" />
|
||||||
|
</p>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="群公告" placement="top">
|
||||||
|
<p v-show="params.talk_type == 2">
|
||||||
|
<i class="iconfont icon-gonggao2" @click="triggerEvent('notice')" />
|
||||||
|
</p>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="群设置" placement="top">
|
||||||
|
<p v-show="params.talk_type == 2">
|
||||||
|
<i class="el-icon-setting" @click="triggerEvent('setting')" />
|
||||||
|
</p>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
talk_type: 0,
|
||||||
|
receiver_id: 0,
|
||||||
|
params: 0,
|
||||||
|
nickname: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
online: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
keyboard: {
|
||||||
|
type: [Boolean, Number],
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
params: {
|
||||||
|
talk_type: 0,
|
||||||
|
receiver_id: 0,
|
||||||
|
params: 0,
|
||||||
|
nickname: '',
|
||||||
|
},
|
||||||
|
isOnline: false,
|
||||||
|
isKeyboard: false,
|
||||||
|
groupNum: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.setParamsData(this.data)
|
||||||
|
this.setOnlineStatus(this.online)
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
data(value) {
|
||||||
|
this.setParamsData(value)
|
||||||
|
},
|
||||||
|
online(value) {
|
||||||
|
this.setOnlineStatus(value)
|
||||||
|
},
|
||||||
|
keyboard(value) {
|
||||||
|
this.isKeyboard = value
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isKeyboard = false
|
||||||
|
}, 2000)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setOnlineStatus(value) {
|
||||||
|
this.isOnline = value
|
||||||
|
},
|
||||||
|
setParamsData(object) {
|
||||||
|
Object.assign(this.params, object)
|
||||||
|
},
|
||||||
|
setGroupNum(value) {
|
||||||
|
this.groupNum = value
|
||||||
|
},
|
||||||
|
triggerEvent(event_name) {
|
||||||
|
this.$emit('event', event_name)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#panel-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-bottom: 1px solid #f5eeee;
|
||||||
|
|
||||||
|
.module {
|
||||||
|
width: 100%/3;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-module {
|
||||||
|
padding-right: 5px;
|
||||||
|
|
||||||
|
.icon-badge {
|
||||||
|
background: rgb(81 139 254);
|
||||||
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
padding: 1px 3px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: white;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin-right: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.red-color {
|
||||||
|
background: #f97348;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-module {
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.online {
|
||||||
|
color: #cccccc;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 15px;
|
||||||
|
|
||||||
|
&.color {
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.online-status {
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
display: inline-block;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-radius: 50%;
|
||||||
|
position: relative;
|
||||||
|
background-color: #1890ff;
|
||||||
|
margin-right: 5px;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
position: absolute;
|
||||||
|
top: -1px;
|
||||||
|
left: -1px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid #1890ff;
|
||||||
|
border-radius: 50%;
|
||||||
|
-webkit-animation: antStatusProcessing 1.2s ease-in-out infinite;
|
||||||
|
animation: antStatusProcessing 1.2s ease-in-out infinite;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.keyboard-status {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 10px;
|
||||||
|
animation: inputfade 600ms infinite;
|
||||||
|
-webkit-animation: inputfade 600ms infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-module {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0 8px;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #828f95;
|
||||||
|
&:active i {
|
||||||
|
font-size: 26px;
|
||||||
|
transform: scale(1.3);
|
||||||
|
transition: ease 0.5s;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* css 动画 */
|
||||||
|
@keyframes inputfade {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes inputfade {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes antStatusProcessing {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: scale(0.8);
|
||||||
|
transform: scale(0.8);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
-webkit-transform: scale(2.4);
|
||||||
|
transform: scale(2.4);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes antStatusProcessing {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: scale(0.8);
|
||||||
|
transform: scale(0.8);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
-webkit-transform: scale(2.4);
|
||||||
|
transform: scale(2.4);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,101 @@
|
||||||
|
<template>
|
||||||
|
<div class="multi-select">
|
||||||
|
<div class="multi-title">
|
||||||
|
<span>已选中:{{ value }} 条消息</span>
|
||||||
|
</div>
|
||||||
|
<div class="multi-main">
|
||||||
|
<div class="btn-group">
|
||||||
|
<div
|
||||||
|
class="multi-icon pointer"
|
||||||
|
@click="$emit('event', 'merge_forward')"
|
||||||
|
>
|
||||||
|
<i class="el-icon-position" />
|
||||||
|
</div>
|
||||||
|
<p>合并转发</p>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<div class="multi-icon pointer" @click="$emit('event', 'forward')">
|
||||||
|
<i class="el-icon-position" />
|
||||||
|
</div>
|
||||||
|
<p>逐条转发</p>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<div class="multi-icon pointer" @click="$emit('event', 'delete')">
|
||||||
|
<i class="el-icon-delete" />
|
||||||
|
</div>
|
||||||
|
<p>批量删除</p>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<div class="multi-icon pointer" @click="$emit('event', 'close')">
|
||||||
|
<i class="el-icon-close" />
|
||||||
|
</div>
|
||||||
|
<p>关闭</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.multi-select {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.multi-title {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
color: #878484;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.multi-main {
|
||||||
|
.btn-group {
|
||||||
|
display: inline-block;
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
margin-right: 15px;
|
||||||
|
|
||||||
|
.multi-icon {
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 auto;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: red;
|
||||||
|
border-color: red;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,239 @@
|
||||||
|
<template>
|
||||||
|
<div class="box" @scroll="scrollBottom">
|
||||||
|
<div class="tab">
|
||||||
|
<el-tabs v-model="activeName" @tab-click="handleClick" :stretch=true>
|
||||||
|
<el-tab-pane label="最近浏览" name="goods">
|
||||||
|
<dl>
|
||||||
|
<dd v-for="item in list" v-infinite-scroll="loadMore">
|
||||||
|
<div class="base">
|
||||||
|
<div>
|
||||||
|
<img :src="item.thumbnail" class="image" />
|
||||||
|
</div>
|
||||||
|
<div style="margin-left: 13px">
|
||||||
|
<a class="goods_name" @click="linkToGoods(item.goodsId, item.id)">{{ item.goodsName }}</a>
|
||||||
|
<div style="margin-top: 8px;">
|
||||||
|
<span style="color: red;">¥{{ item.price }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button class="store-button" type="danger" v-if="item.btnHide == 1" size="mini"
|
||||||
|
@click="submitSendGoodsMessage(item)" plain>发送</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="订单列表" name="orders">
|
||||||
|
<dl>
|
||||||
|
<dd v-for="(item, index) in orderList" v-infinite-scroll="loadMore" :key="index">
|
||||||
|
<div style="margin-bottom: 20px;">
|
||||||
|
<span class="orderSn">订单号:{{ item.sn }}</span>
|
||||||
|
<img :src="item.groupImages" alt=""
|
||||||
|
style="height: 100px; width: 100px;margin-top: 10px; vertical-align: middle; ">
|
||||||
|
<span class="orderGoodsName" @click="linkToOrders(item.sn)"> {{ item.groupName }}</span>
|
||||||
|
<span style="margin-left: 10px; color: red;">{{ item.paymentTime }}</span>
|
||||||
|
<div class="orderBtn">
|
||||||
|
<el-button type="danger" class="store-button" v-if="item.btnHide == 1" size="mini"
|
||||||
|
@click="submitSendOrderMessage(item, index)" plain>发送</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Tag, button, Tabs, TabPane, InfiniteScroll } from 'element-ui'
|
||||||
|
import { mapState, mapGetters } from "vuex";
|
||||||
|
export default {
|
||||||
|
directives: {
|
||||||
|
"infinite-scroll": InfiniteScroll,
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
activeName: 'goods',
|
||||||
|
btnHide: undefined,
|
||||||
|
hide: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(["talkItems"]),
|
||||||
|
...mapState({
|
||||||
|
id: (state) => state.user.id,
|
||||||
|
|
||||||
|
toUser: (state) => state.user.toUser,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
"el-tag": Tag,
|
||||||
|
"el-button": button,
|
||||||
|
"el-tabs": Tabs,
|
||||||
|
"el-tab-pane": TabPane,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
//跳转订单列表
|
||||||
|
|
||||||
|
scrollBottom (e) {
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = e.srcElement
|
||||||
|
if (scrollTop + clientHeight >= scrollHeight) {
|
||||||
|
this.$emit('loadMore')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadMore () {
|
||||||
|
|
||||||
|
},
|
||||||
|
// 发送消息回调事件
|
||||||
|
submitSendGoodsMessage (item) {
|
||||||
|
const context = {
|
||||||
|
id: item.id,
|
||||||
|
goodsId: item.goodsId,
|
||||||
|
thumbnail: item.thumbnail,
|
||||||
|
price: item.price,
|
||||||
|
goodsName: item.goodsName
|
||||||
|
}
|
||||||
|
const record = {
|
||||||
|
operation_type: "MESSAGE",
|
||||||
|
to: this.toUser.userId,
|
||||||
|
from: this.id,
|
||||||
|
message_type: "GOODS",
|
||||||
|
context: context,
|
||||||
|
talk_id: this.toUser.id,
|
||||||
|
};
|
||||||
|
this.$emit('sendMessage', record, context, 'GOODS');
|
||||||
|
localStorage.setItem(item.goodsId, 0)
|
||||||
|
item.btnHide = 0
|
||||||
|
},
|
||||||
|
// 发送订单列表
|
||||||
|
submitSendOrderMessage (item, index) {
|
||||||
|
const context = {
|
||||||
|
sn: item.sn,
|
||||||
|
groupImages: item.groupImages,
|
||||||
|
paymentTime: item.paymentTime,
|
||||||
|
groupName: item.groupName,
|
||||||
|
}
|
||||||
|
const record = {
|
||||||
|
operation_type: "MESSAGE",
|
||||||
|
to: this.toUser.userId,
|
||||||
|
from: this.id,
|
||||||
|
message_type: "ORDER",
|
||||||
|
context: context,
|
||||||
|
talk_id: this.toUser.id,
|
||||||
|
};
|
||||||
|
this.$emit('sendMessage', record, context, 'ORDER');
|
||||||
|
localStorage.setItem(item.goodsId, 0)
|
||||||
|
item.btnHide = 0
|
||||||
|
},
|
||||||
|
handleClick (tab, event) {
|
||||||
|
console.log(tab, event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
orderList: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
console.log(this.orderList, 'orderList');
|
||||||
|
this.btnHide = localStorage.getItem('btnHide')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.orderGoodsName {
|
||||||
|
width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
position: absolute;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderSn {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderBtn {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-right: 15px;
|
||||||
|
position: relative;
|
||||||
|
bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods_name {
|
||||||
|
text-overflow: -o-ellipsis-lastline;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-tabs__item.is-top:last-child {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/.el-tabs__active-bar {
|
||||||
|
background-color: #f23030;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-tabs__nav.is-top {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
height: 500px;
|
||||||
|
overflow: auto;
|
||||||
|
width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.store-button {
|
||||||
|
background-color: white;
|
||||||
|
border-color: #F56C6C;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.base {
|
||||||
|
margin-top: 5px;
|
||||||
|
height: 120px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.price {
|
||||||
|
color: red;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
height: 100px;
|
||||||
|
margin-top: 3px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.separate {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,186 @@
|
||||||
|
<template>
|
||||||
|
<div style="width: 350px;">
|
||||||
|
当前浏览
|
||||||
|
<div class="base">
|
||||||
|
<div>
|
||||||
|
<img :src="goodsDetail.thumbnail" class="image" />
|
||||||
|
</div>
|
||||||
|
<div style="margin-left: 13px">
|
||||||
|
<a @click="linkToGoods(goodsDetail.goodsId, goodsDetail.id)"> {{ goodsDetail.goodsName }} </a>
|
||||||
|
<div>
|
||||||
|
<span style="color: red;">¥{{ goodsDetail.price }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="hide">
|
||||||
|
<el-button class="store-button" type="danger" v-if="!sendFlag && btnHide == 1" size="mini"
|
||||||
|
@click="submitSendMessage()" plain>发送</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="separate" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Tag, button } from 'element-ui'
|
||||||
|
import { mapState, mapGetters } from "vuex";
|
||||||
|
import SocketInstance from "@/im-server/socket-instance";
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
sendFlag: false,
|
||||||
|
btnHide: undefined,
|
||||||
|
hide: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(["talkItems"]),
|
||||||
|
...mapState({
|
||||||
|
id: (state) => state.user.id,
|
||||||
|
index_name: (state) => state.dialogue.index_name,
|
||||||
|
toUser: (state) => state.user.toUser,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.btnHide = localStorage.getItem('btnHide')
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
"el-tag": Tag,
|
||||||
|
"el-button": button,
|
||||||
|
Storage
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toGoods () {
|
||||||
|
alert("toGoods")
|
||||||
|
},
|
||||||
|
toMessage () {
|
||||||
|
alert(JSON.stringify(this.toUser))
|
||||||
|
alert("toMessage")
|
||||||
|
},
|
||||||
|
// 回车键发送消息回调事件
|
||||||
|
submitSendMessage () {
|
||||||
|
console.log("发送");
|
||||||
|
const context = this.goodsDetail
|
||||||
|
const record = {
|
||||||
|
operation_type: "MESSAGE",
|
||||||
|
to: this.toUser.userId,
|
||||||
|
from: this.id,
|
||||||
|
message_type: "GOODS",
|
||||||
|
context: context,
|
||||||
|
talk_id: this.toUser.id,
|
||||||
|
};
|
||||||
|
SocketInstance.emit("event_talk", record);
|
||||||
|
|
||||||
|
this.$store.commit("UPDATE_TALK_ITEM", {
|
||||||
|
index_name: this.index_name,
|
||||||
|
draft_text: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入数据
|
||||||
|
*/
|
||||||
|
const insterChat = {
|
||||||
|
createTime: this.formateDateAndTimeToString(new Date()),
|
||||||
|
fromUser: this.id,
|
||||||
|
toUser: record.to,
|
||||||
|
isRead: false,
|
||||||
|
messageType: "GOODS",
|
||||||
|
text: context,
|
||||||
|
float: "right",
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("insterChat", insterChat);
|
||||||
|
// console.log("插入对话记录",'')
|
||||||
|
// 插入对话记录
|
||||||
|
this.$store.commit("PUSH_DIALOGUE", insterChat);
|
||||||
|
// 获取聊天面板元素节点
|
||||||
|
let el = document.getElementById("lumenChatPanel");
|
||||||
|
// 判断的滚动条是否在底部
|
||||||
|
let isBottom =
|
||||||
|
Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight;
|
||||||
|
|
||||||
|
if (isBottom || record.to == this.id) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
el.scrollTop = el.scrollHeight;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$store.commit("SET_TLAK_UNREAD_MESSAGE", {
|
||||||
|
content: content,
|
||||||
|
nickname: record.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 发送后隐藏按钮 0:隐藏 1:显示
|
||||||
|
localStorage.setItem('btnHide', 0)
|
||||||
|
this.hide = false
|
||||||
|
},
|
||||||
|
|
||||||
|
formateDateAndTimeToString (date) {
|
||||||
|
var hours = date.getHours();
|
||||||
|
var mins = date.getMinutes();
|
||||||
|
var secs = date.getSeconds();
|
||||||
|
var msecs = date.getMilliseconds();
|
||||||
|
if (hours < 10) hours = "0" + hours;
|
||||||
|
if (mins < 10) mins = "0" + mins;
|
||||||
|
if (secs < 10) secs = "0" + secs;
|
||||||
|
if (msecs < 10) secs = "0" + msecs;
|
||||||
|
return (
|
||||||
|
this.formatDateToString(date) + " " + hours + ":" + mins + ":" + secs
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
formatDateToString (date) {
|
||||||
|
var year = date.getFullYear();
|
||||||
|
var month = date.getMonth() + 1;
|
||||||
|
var day = date.getDate();
|
||||||
|
if (month < 10) month = "0" + month;
|
||||||
|
if (day < 10) day = "0" + day;
|
||||||
|
return year + "-" + month + "-" + day;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
goodsDetail: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.store-button {
|
||||||
|
background-color: white;
|
||||||
|
border-color: #F56C6C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.base {
|
||||||
|
margin-top: 5px;
|
||||||
|
height: 120px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
div {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-top: 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
height: 100px;
|
||||||
|
margin-top: 3px;
|
||||||
|
width: 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.click-button {
|
||||||
|
margin-top: 8px;
|
||||||
|
background-color: white;
|
||||||
|
border-color: #F56C6C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separate {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,77 @@
|
||||||
|
<template>
|
||||||
|
<div style="width: 362px;">
|
||||||
|
<div class="base">
|
||||||
|
<div>
|
||||||
|
<img :src="storeInfo.storeLogo" class="image" />
|
||||||
|
</div>
|
||||||
|
<div style="margin-left: 13px">
|
||||||
|
<div class="div-zoom">
|
||||||
|
{{ storeInfo.storeName }}
|
||||||
|
<el-tag type="danger" v-if="storeInfo.selfOperated" size="mini">自营</el-tag>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
联系方式: {{ storeInfo.memberName }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button class="store-button" type="danger" @click="linkToStore(storeInfo.id)" size="mini"
|
||||||
|
plain>进入店铺</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="separate" />
|
||||||
|
<div class="separate">店铺评分: <span>{{ storeInfo.serviceScore }}</span></div>
|
||||||
|
<div class="separate">服务评分: <span>{{ storeInfo.descriptionScore }}</span></div>
|
||||||
|
<div class="separate">物流评分: <span>{{ storeInfo.deliveryScore }}</span></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Tag, button } from 'element-ui'
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
"el-tag": Tag,
|
||||||
|
"el-button": button,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
storeInfo: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.store-button {
|
||||||
|
background-color: white;
|
||||||
|
border-color: #F56C6C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.base {
|
||||||
|
margin-top: 5px;
|
||||||
|
height: 120px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
div {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
height: 100px;
|
||||||
|
margin-top: 3px;
|
||||||
|
width: 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.separate {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,506 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-container class="editor-container">
|
||||||
|
<el-header class="no-padding toolbar" height="35px">
|
||||||
|
<ul>
|
||||||
|
<li v-popover:popoverEmoticon>
|
||||||
|
<i class="iconfont icon-icon_im_face" style="font-size: 15px" />
|
||||||
|
<p class="tip-title">表情符号</p>
|
||||||
|
</li>
|
||||||
|
<!-- <li @click="codeBlock.isShow = true">
|
||||||
|
<i class="iconfont icon-daima" />
|
||||||
|
<p class="tip-title">代码片段</p>
|
||||||
|
</li>
|
||||||
|
<li @click="recorder = true">
|
||||||
|
<i class="el-icon-headset" />
|
||||||
|
<p class="tip-title">语音消息</p>
|
||||||
|
</li> -->
|
||||||
|
<!-- #TODO 发图片功能暂时隐藏 此处会涉及到token过期 -->
|
||||||
|
<!-- <li @click="$refs.restFile.click()">
|
||||||
|
<i class="el-icon-picture-outline-round" />
|
||||||
|
<p class="tip-title">图片</p>
|
||||||
|
</li> -->
|
||||||
|
<!-- <li @click="$refs.restFile2.click()">
|
||||||
|
<i class="el-icon-folder" />
|
||||||
|
<p class="tip-title">附件</p>
|
||||||
|
</li>
|
||||||
|
<li @click="filesManager.isShow = true">
|
||||||
|
<i class="el-icon-folder-opened" />
|
||||||
|
<p class="tip-title">上传管理</p>
|
||||||
|
</li>
|
||||||
|
<li v-show="isGroupTalk" @click="vote.isShow = true">
|
||||||
|
<i class="el-icon-s-data" />
|
||||||
|
<p class="tip-title">发起投票</p>
|
||||||
|
</li> -->
|
||||||
|
|
||||||
|
<!-- <p class="text-tips no-select">-->
|
||||||
|
<!-- <span>按Enter发送 / Shift+Enter 换行</span>-->
|
||||||
|
<!-- <el-popover placement="top-end" width="600" trigger="click">-->
|
||||||
|
<!-- <div class="editor-books">-->
|
||||||
|
<!-- <div class="books-title">编辑说明:</div>-->
|
||||||
|
<!-- <p>-->
|
||||||
|
<!-- 1.-->
|
||||||
|
<!-- 支持上传QQ及微信截图,在QQ或微信中截图后使用Ctrl+v上传图片。-->
|
||||||
|
<!-- </p>-->
|
||||||
|
<!-- <p>-->
|
||||||
|
<!-- 2.-->
|
||||||
|
<!-- 支持浏览器及Word文档中的图片复制上传、复制后使用Ctrl+v上传图片。-->
|
||||||
|
<!-- </p>-->
|
||||||
|
<!-- <p>3. 支持图片拖拽上传。</p>-->
|
||||||
|
<!-- <p>4. 支持文件上传 ( 文件小于100M ) 。</p>-->
|
||||||
|
<!-- <p>5. 按Enter发送 / Shift+Enter 换行。</p>-->
|
||||||
|
<!-- <p>-->
|
||||||
|
<!-- 6.-->
|
||||||
|
<!-- 注意:当文件正在上传时,请勿关闭网页或离开当前对话框,否则将导致文件停止上传或上传失败。-->
|
||||||
|
<!-- </p>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <i class="el-icon-info" slot="reference" />-->
|
||||||
|
<!-- </el-popover>-->
|
||||||
|
<!-- </p>-->
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<el-popover
|
||||||
|
ref="popoverEmoticon"
|
||||||
|
placement="top-start"
|
||||||
|
trigger="click"
|
||||||
|
width="300"
|
||||||
|
popper-class="no-padding el-popover-em"
|
||||||
|
>
|
||||||
|
<MeEditorEmoticon ref="editorEmoticon" @selected="selecteEmoticon" />
|
||||||
|
</el-popover>
|
||||||
|
|
||||||
|
<form
|
||||||
|
enctype="multipart/form-data"
|
||||||
|
style="display: none"
|
||||||
|
ref="fileFrom"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
ref="restFile"
|
||||||
|
accept="image/*"
|
||||||
|
@change="uploadImageChange"
|
||||||
|
/>
|
||||||
|
<input type="file" ref="restFile2" @change="uploadFileChange" />
|
||||||
|
</form>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="no-padding textarea">
|
||||||
|
<textarea
|
||||||
|
ref="textarea"
|
||||||
|
v-paste="pasteImage"
|
||||||
|
v-drag="dragPasteImage"
|
||||||
|
v-model.trim="editorText"
|
||||||
|
rows="6"
|
||||||
|
placeholder="你想要的聊点什么呢 ..."
|
||||||
|
@keydown="keydownEvent($event)"
|
||||||
|
@input="inputEvent($event)"
|
||||||
|
/>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
|
||||||
|
<!-- 图片查看器 -->
|
||||||
|
<MeEditorImageView
|
||||||
|
ref="imageViewer"
|
||||||
|
v-model="imageViewer.isShow"
|
||||||
|
:file="imageViewer.file"
|
||||||
|
@confirm="confirmUploadImage"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MeEditorRecorder v-if="recorder" @close="recorder = false" />
|
||||||
|
|
||||||
|
<!-- 代码块编辑器 -->
|
||||||
|
<TalkCodeBlock
|
||||||
|
v-if="codeBlock.isShow"
|
||||||
|
:edit-mode="codeBlock.editMode"
|
||||||
|
@close="codeBlock.isShow = false"
|
||||||
|
@confirm="confirmCodeBlock"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文件上传管理器 -->
|
||||||
|
<MeEditorFileManage ref="filesManager" v-model="filesManager.isShow" />
|
||||||
|
|
||||||
|
<MeEditorVote
|
||||||
|
v-if="vote.isShow"
|
||||||
|
@close="
|
||||||
|
() => {
|
||||||
|
this.vote.isShow = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MeEditorEmoticon from "./MeEditorEmoticon";
|
||||||
|
import MeEditorFileManage from "./MeEditorFileManage";
|
||||||
|
import MeEditorImageView from "./MeEditorImageView";
|
||||||
|
import MeEditorRecorder from "./MeEditorRecorder";
|
||||||
|
import MeEditorVote from "./MeEditorVote";
|
||||||
|
import TalkCodeBlock from "@/components/chat/TalkCodeBlock";
|
||||||
|
import { getPasteImgs, getDragPasteImg } from "@/utils/editor";
|
||||||
|
import { findTalk } from "@/utils/talk";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ServeSendTalkCodeBlock,
|
||||||
|
ServeSendTalkImage,
|
||||||
|
ServeSendEmoticon,
|
||||||
|
} from "@/api/chat";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MeEditor",
|
||||||
|
components: {
|
||||||
|
MeEditorEmoticon,
|
||||||
|
MeEditorFileManage,
|
||||||
|
MeEditorImageView,
|
||||||
|
TalkCodeBlock,
|
||||||
|
MeEditorRecorder,
|
||||||
|
MeEditorVote,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
talkUser() {
|
||||||
|
return this.$store.state.dialogue.index_name;
|
||||||
|
},
|
||||||
|
isGroupTalk() {
|
||||||
|
return this.$store.state.dialogue.talk_type == 2;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
talkUser(n_index_name) {
|
||||||
|
this.$refs.filesManager.clear();
|
||||||
|
this.editorText = this.getDraftText(n_index_name);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 当前编辑的内容
|
||||||
|
editorText: "",
|
||||||
|
|
||||||
|
// 图片查看器相关信息
|
||||||
|
imageViewer: {
|
||||||
|
isShow: false,
|
||||||
|
file: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
codeBlock: {
|
||||||
|
isShow: false,
|
||||||
|
editMode: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
filesManager: {
|
||||||
|
isShow: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
vote: {
|
||||||
|
isShow: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 录音器
|
||||||
|
recorder: false,
|
||||||
|
|
||||||
|
// 上次发送消息的时间
|
||||||
|
sendtime: 0,
|
||||||
|
|
||||||
|
// 发送间隔时间(默认1秒)
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 读取对话编辑草稿信息 并赋值给当前富文本
|
||||||
|
getDraftText(index_name) {
|
||||||
|
console.log("findTalk(index_name)", findTalk(index_name));
|
||||||
|
return findTalk(index_name)?.draft_text || "";
|
||||||
|
},
|
||||||
|
|
||||||
|
//复制粘贴图片回调方法
|
||||||
|
pasteImage(e) {
|
||||||
|
let files = getPasteImgs(e);
|
||||||
|
if (files.length == 0) return;
|
||||||
|
|
||||||
|
this.openImageViewer(files[0]);
|
||||||
|
},
|
||||||
|
|
||||||
|
//拖拽上传图片回调方法
|
||||||
|
dragPasteImage(e) {
|
||||||
|
let files = getDragPasteImg(e);
|
||||||
|
if (files.length == 0) return;
|
||||||
|
|
||||||
|
this.openImageViewer(files[0]);
|
||||||
|
},
|
||||||
|
|
||||||
|
inputEvent(e) {
|
||||||
|
this.$emit("keyboard-event", e.target.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 键盘按下监听事件
|
||||||
|
keydownEvent(e) {
|
||||||
|
if (e.keyCode == 13 && this.editorText == "") {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回车发送消息
|
||||||
|
if (e.keyCode == 13 && e.shiftKey == false && this.editorText != "") {
|
||||||
|
let currentTime = new Date().getTime();
|
||||||
|
|
||||||
|
if (this.sendtime > 0) {
|
||||||
|
// 判断 1秒内只能发送一条消息
|
||||||
|
if (currentTime - this.sendtime < this.interval) {
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit("send", this.editorText);
|
||||||
|
this.editorText = "";
|
||||||
|
this.sendtime = currentTime;
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选择图片文件后回调方法
|
||||||
|
uploadImageChange(e) {
|
||||||
|
this.openImageViewer(e.target.files[0]);
|
||||||
|
this.$refs.restFile.value = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选择文件回调事件
|
||||||
|
uploadFileChange(e) {
|
||||||
|
let maxsize = 100 * 1024 * 1024;
|
||||||
|
if (e.target.files.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = e.target.files[0];
|
||||||
|
if (/\.(gif|jpg|jpeg|png|webp|GIF|JPG|PNG|WEBP)$/.test(file.name)) {
|
||||||
|
this.openImageViewer(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.size > maxsize) {
|
||||||
|
this.$notify.info({
|
||||||
|
title: "消息",
|
||||||
|
message: "上传文件不能大于100M",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.filesManager.isShow = true;
|
||||||
|
this.$refs.restFile2.value = null;
|
||||||
|
this.$refs.filesManager.upload(file);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 打开图片查看器
|
||||||
|
openImageViewer(file) {
|
||||||
|
this.imageViewer.isShow = true;
|
||||||
|
this.imageViewer.file = file;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 代码块编辑器确认完成回调事件
|
||||||
|
confirmCodeBlock(data) {
|
||||||
|
const { talk_type, receiver_id } = this.$store.state.dialogue;
|
||||||
|
ServeSendTalkCodeBlock({
|
||||||
|
talk_type,
|
||||||
|
receiver_id,
|
||||||
|
code: data.code,
|
||||||
|
lang: data.language,
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.codeBlock.isShow = false;
|
||||||
|
} else {
|
||||||
|
this.$notify({
|
||||||
|
title: "友情提示",
|
||||||
|
message: res.message,
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 确认上传图片消息回调事件
|
||||||
|
confirmUploadImage() {
|
||||||
|
let fileData = new FormData();
|
||||||
|
fileData.append("file", this.imageViewer.file);
|
||||||
|
|
||||||
|
let ref = this.$refs.imageViewer;
|
||||||
|
|
||||||
|
ServeSendTalkImage(fileData)
|
||||||
|
.then((res) => {
|
||||||
|
ref.loading = false;
|
||||||
|
if (res.code == 200) {
|
||||||
|
ref.closeBox();
|
||||||
|
} else {
|
||||||
|
this.$notify({
|
||||||
|
title: "友情提示",
|
||||||
|
message: res.message,
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
ref.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选中表情包回调事件
|
||||||
|
selecteEmoticon(data) {
|
||||||
|
if (data.type == 1) {
|
||||||
|
let value = this.editorText;
|
||||||
|
let el = this.$refs.textarea;
|
||||||
|
let startPos = el.selectionStart;
|
||||||
|
let endPos = el.selectionEnd;
|
||||||
|
let newValue =
|
||||||
|
value.substring(0, startPos) +
|
||||||
|
data.value +
|
||||||
|
value.substring(endPos, value.length);
|
||||||
|
|
||||||
|
this.editorText = newValue;
|
||||||
|
|
||||||
|
if (el.setSelectionRange) {
|
||||||
|
setTimeout(() => {
|
||||||
|
let index = startPos + data.value.length;
|
||||||
|
el.setSelectionRange(index, index);
|
||||||
|
el.focus();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const { talk_type, receiver_id } = this.$store.state.dialogue;
|
||||||
|
ServeSendEmoticon({
|
||||||
|
talk_type,
|
||||||
|
receiver_id,
|
||||||
|
emoticon_id: data.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.popoverEmoticon.doClose();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.editor-container {
|
||||||
|
height: 160px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .toolbar {
|
||||||
|
line-height: 35px;
|
||||||
|
border-bottom: 1px solid #f5f0f0;
|
||||||
|
border-top: 1px solid #f5f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .toolbar li {
|
||||||
|
list-style: none;
|
||||||
|
float: left;
|
||||||
|
width: 35px;
|
||||||
|
margin-left: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 35px;
|
||||||
|
position: relative;
|
||||||
|
color: #8d8d8d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .toolbar li .tip-title {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 38px;
|
||||||
|
left: 0px;
|
||||||
|
height: 26px;
|
||||||
|
line-height: 26px;
|
||||||
|
background-color: rgba(31, 35, 41, 0.9);
|
||||||
|
color: white;
|
||||||
|
min-width: 30px;
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 2px;
|
||||||
|
white-space: pre;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .toolbar li:hover .tip-title {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .toolbar li:hover {
|
||||||
|
background-color: #f7f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .toolbar .text-tips {
|
||||||
|
float: right;
|
||||||
|
margin-right: 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .toolbar .text-tips i {
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 5px;
|
||||||
|
color: rgb(255, 181, 111);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .textarea {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
width: -moz-calc(100% - 10px);
|
||||||
|
width: -webkit-calc(100% - 10px);
|
||||||
|
height: calc(100% - 10px);
|
||||||
|
height: -moz-calc(100% - 10px);
|
||||||
|
height: -webkit-calc(100% - 10px);
|
||||||
|
border: 0 none;
|
||||||
|
outline: none;
|
||||||
|
resize: none;
|
||||||
|
font-size: 15px;
|
||||||
|
overflow-y: auto;
|
||||||
|
color: #464545;
|
||||||
|
padding: 5px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea::-webkit-scrollbar-thumb {
|
||||||
|
background: #d5cfcf;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea::-webkit-scrollbar-track {
|
||||||
|
background: #ededed;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea::-webkit-input-placeholder {
|
||||||
|
color: #dccdcd;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 编辑器文档说明 --- start */
|
||||||
|
.editor-books .books-title {
|
||||||
|
font-size: 16px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 22px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #cbcbcb;
|
||||||
|
color: #726f6f;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-left: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-books p {
|
||||||
|
text-indent: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
color: #7f7c7c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 编辑器文档说明 --- end */
|
||||||
|
</style>
|
|
@ -0,0 +1,345 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-container class="container">
|
||||||
|
<el-main class="no-padding main lum-scrollbar">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
ref="fileCustomEmoji"
|
||||||
|
accept="image/*"
|
||||||
|
style="display: none"
|
||||||
|
@change="customUploadEmoji"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div v-show="showEmoticonId == -1" class="emoticon">
|
||||||
|
<div class="title">QQ表情</div>
|
||||||
|
<div
|
||||||
|
v-for="(elImg, text) in emoji.emojis"
|
||||||
|
v-html="elImg"
|
||||||
|
:key="text"
|
||||||
|
class="emoticon-item"
|
||||||
|
@click="clickEmoticon(text)"
|
||||||
|
></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
<div class="title">符号表情</div>
|
||||||
|
<div
|
||||||
|
v-for="(item, i) in emoji.symbol"
|
||||||
|
:key="i"
|
||||||
|
class="emoticon-item symbol"
|
||||||
|
@click="clickEmoticon(item)"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="item in emojiItem.slice(1)"
|
||||||
|
v-show="item.emoticon_id == showEmoticonId"
|
||||||
|
:key="item.emoticon_id"
|
||||||
|
class="emoji-box"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="item.emoticon_id == 0"
|
||||||
|
class="emoji-item custom-emoji"
|
||||||
|
@click="$refs.fileCustomEmoji.click()"
|
||||||
|
>
|
||||||
|
<i class="el-icon-picture" />
|
||||||
|
<span>自定义</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="subitem in item.list"
|
||||||
|
:key="subitem.src"
|
||||||
|
class="emoji-item"
|
||||||
|
@click="clickImageEmoticon(subitem)"
|
||||||
|
>
|
||||||
|
<el-image :src="subitem.src" fit="cover" />
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
<!-- <el-footer height="40px" class="no-padding footer">
|
||||||
|
<div class="toolbar-items">
|
||||||
|
<div
|
||||||
|
v-show="emojiItem.length > 13"
|
||||||
|
class="toolbar-item prev-page"
|
||||||
|
@click="turnPage(1)"
|
||||||
|
>
|
||||||
|
<i class="el-icon-caret-left" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in showItems"
|
||||||
|
:key="index"
|
||||||
|
class="toolbar-item"
|
||||||
|
@click="triggerItem(item)"
|
||||||
|
>
|
||||||
|
<img :src="item.url" />
|
||||||
|
<p class="title">{{ item.name }}</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-show="emojiItem.length > 13 && showItems.length == 13"
|
||||||
|
class="toolbar-item next-page"
|
||||||
|
@click="turnPage(2)"
|
||||||
|
>
|
||||||
|
<i class="el-icon-caret-right" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-footer> -->
|
||||||
|
</el-container>
|
||||||
|
|
||||||
|
<MeEditorSystemEmoticon
|
||||||
|
v-if="systemEmojiBox"
|
||||||
|
@close="systemEmojiBox = false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MeEditorSystemEmoticon from "@/components/editor/MeEditorSystemEmoticon";
|
||||||
|
import { emojiList as emoji } from "@/utils/emojis";
|
||||||
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MeEditorEmoticon",
|
||||||
|
components: {
|
||||||
|
MeEditorSystemEmoticon,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
emojiItem: (state) => state.emoticon.items,
|
||||||
|
}),
|
||||||
|
showItems() {
|
||||||
|
let start = (this.page - 1) * this.pageSize;
|
||||||
|
let end = start + this.pageSize;
|
||||||
|
return this.emojiItem.slice(start, end);
|
||||||
|
},
|
||||||
|
pageTotal() {
|
||||||
|
return this.emojiItem.length / this.pageSize;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
emoji,
|
||||||
|
|
||||||
|
// 系统表情包套弹出窗
|
||||||
|
systemEmojiBox: false,
|
||||||
|
|
||||||
|
showEmoticonId: -1,
|
||||||
|
showTitle: "QQ表情/符号表情",
|
||||||
|
|
||||||
|
page: 1,
|
||||||
|
pageSize: 13,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$store.commit("LOAD_USER_EMOTICON");
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 表情包导航翻页
|
||||||
|
turnPage(type) {
|
||||||
|
if (type == 1) {
|
||||||
|
if (this.page == 1) return false;
|
||||||
|
this.page--;
|
||||||
|
} else {
|
||||||
|
if (this.page >= this.pageTotal) return false;
|
||||||
|
this.page++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 点击表情包导航
|
||||||
|
triggerItem(item) {
|
||||||
|
this.showEmoticonId = item.emoticon_id;
|
||||||
|
this.showTitle = item.name;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选中表情
|
||||||
|
clickEmoticon(emoji) {
|
||||||
|
this.callback({
|
||||||
|
type: 1,
|
||||||
|
value: emoji,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 发送图片表情包
|
||||||
|
clickImageEmoticon(item) {
|
||||||
|
this.callback({
|
||||||
|
type: 2,
|
||||||
|
value: item.media_id,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
callback(data) {
|
||||||
|
this.$emit("selected", data);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 自定义上传表情
|
||||||
|
customUploadEmoji(e) {
|
||||||
|
if (e.target.files.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.commit("UPLOAD_USER_EMOTICON", {
|
||||||
|
file: e.target.files[0],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.container {
|
||||||
|
height: 300px;
|
||||||
|
max-width: 500px;
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
line-height: 30px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
padding-left: 5px;
|
||||||
|
user-select: none;
|
||||||
|
position: relative;
|
||||||
|
border-bottom: 1px solid #fbf5f5;
|
||||||
|
|
||||||
|
.addbtn {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 1px;
|
||||||
|
color: #409eff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
background-color: #eff1f7;
|
||||||
|
|
||||||
|
.toolbar-items {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.toolbar-item {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
margin: 0 2px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: -25px;
|
||||||
|
left: 0px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
background: #353434;
|
||||||
|
color: white;
|
||||||
|
min-width: 30px;
|
||||||
|
font-size: 10px;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
border-radius: 2px;
|
||||||
|
white-space: pre;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .title {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container .footer .toolbar-items .prev-page:active i,
|
||||||
|
.container .footer .toolbar-items .next-page:active i {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-box,
|
||||||
|
.emoticon {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoticon {
|
||||||
|
.title {
|
||||||
|
width: 50%;
|
||||||
|
height: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
color: #ccc;
|
||||||
|
font-weight: 400;
|
||||||
|
padding-left: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoticon-item {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
margin: 2px;
|
||||||
|
float: left;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.symbol {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-box {
|
||||||
|
.emoji-item {
|
||||||
|
width: 67px;
|
||||||
|
height: 67px;
|
||||||
|
margin: 2px;
|
||||||
|
background-color: #eff1f7;
|
||||||
|
float: left;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: ease-in 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-emoji {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 10px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 30px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transition: ease-in 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-box .emoji-item:hover .el-image,
|
||||||
|
.emoji-box .emoji-item:hover {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,440 @@
|
||||||
|
<template>
|
||||||
|
<el-container
|
||||||
|
class="container animated bounceInUp"
|
||||||
|
v-outside="closeBox"
|
||||||
|
v-if="show"
|
||||||
|
>
|
||||||
|
<el-header class="no-padding header" height="50px">
|
||||||
|
<p>
|
||||||
|
上传管理 <span v-show="total">({{ successNum }}/{{ total }})</span>
|
||||||
|
</p>
|
||||||
|
<i class="close-btn el-icon-close" @click="closeBox" />
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-main class="no-padding mian lum-scrollbar">
|
||||||
|
<div class="empty-data" v-show="total == 0">
|
||||||
|
<SvgNotData />
|
||||||
|
<p>暂无上传文件</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="file in items"
|
||||||
|
v-show="!file.isDelete"
|
||||||
|
:key="file.hashName"
|
||||||
|
class="file-item"
|
||||||
|
>
|
||||||
|
<div class="file-header">
|
||||||
|
<div class="type-icon">{{ file.ext }}</div>
|
||||||
|
<el-tooltip :content="file.filename" placement="top-start">
|
||||||
|
<div class="filename">{{ file.filename }}</div>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<div class="status">
|
||||||
|
<span v-if="file.status == 0">等待上传</span>
|
||||||
|
<span v-else-if="file.status == 1" style="color: #66b1ff">
|
||||||
|
正在上传...
|
||||||
|
</span>
|
||||||
|
<span v-else-if="file.status == 2" style="color: #67c23a">
|
||||||
|
已完成
|
||||||
|
</span>
|
||||||
|
<span v-else style="color: red">网络异常</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="file-mian">
|
||||||
|
<div class="progress">
|
||||||
|
<el-progress
|
||||||
|
type="dashboard"
|
||||||
|
:percentage="file.progress"
|
||||||
|
:width="50"
|
||||||
|
:color="colors"
|
||||||
|
/>
|
||||||
|
<span class="name">上传进度</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail">
|
||||||
|
<p>
|
||||||
|
文件类型:<span>{{ file.filetype }}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
文件大小:<span>{{ file.filesize }}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
上传时间:<span>{{ file.datetime }}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-show="file.status == 2 || file.status == 3" class="file-means">
|
||||||
|
<div class="btns" @click="removeFile(file.hashName)">删除</div>
|
||||||
|
<div
|
||||||
|
v-show="file.status == 3"
|
||||||
|
class="btns"
|
||||||
|
@click="triggerUpload(file.hashName)"
|
||||||
|
>
|
||||||
|
继续上传
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from 'vue'
|
||||||
|
import { SvgNotData } from '@/core/icons'
|
||||||
|
import { Progress } from 'element-ui'
|
||||||
|
Vue.use(Progress)
|
||||||
|
|
||||||
|
import { ServeFindFileSplitInfo, ServeFileSubareaUpload } from '@/api/upload'
|
||||||
|
import { formatSize, getFileExt, parseTime } from '@/utils/functions'
|
||||||
|
import { ServeSendTalkFile } from '@/api/chat'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MeEditorFileManage',
|
||||||
|
model: {
|
||||||
|
prop: 'show',
|
||||||
|
event: 'close',
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
show: Boolean,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SvgNotData,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
colors: [
|
||||||
|
{
|
||||||
|
color: '#f56c6c',
|
||||||
|
percentage: 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#e6a23c',
|
||||||
|
percentage: 40,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#5cb87a',
|
||||||
|
percentage: 60,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#1989fa',
|
||||||
|
percentage: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#11ce65',
|
||||||
|
percentage: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
items: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
total() {
|
||||||
|
return this.items.filter(item => {
|
||||||
|
return item.isDelete === false
|
||||||
|
}).length
|
||||||
|
},
|
||||||
|
successNum() {
|
||||||
|
return this.items.filter(item => {
|
||||||
|
return item.isDelete === false && item.status == 2
|
||||||
|
}).length
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeBox() {
|
||||||
|
this.$emit('close', false)
|
||||||
|
},
|
||||||
|
|
||||||
|
upload(file) {
|
||||||
|
ServeFindFileSplitInfo({
|
||||||
|
file_name: file.name,
|
||||||
|
file_size: file.size,
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
const { hash_name, split_size } = res.data
|
||||||
|
|
||||||
|
this.items.unshift({
|
||||||
|
hashName: hash_name,
|
||||||
|
originalFile: file,
|
||||||
|
filename: file.name,
|
||||||
|
status: 0, // 文件上传状态 0:等待上传 1:上传中 2:上传完成 3:网络异常
|
||||||
|
progress: 0,
|
||||||
|
filesize: formatSize(file.size),
|
||||||
|
filetype: file.type || '未知',
|
||||||
|
datetime: parseTime(new Date(), '{m}-{d} {h}:{i}'),
|
||||||
|
ext: getFileExt(file.name),
|
||||||
|
forms: this.fileSlice(file, hash_name, split_size),
|
||||||
|
successNum: 0,
|
||||||
|
isDelete: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.triggerUpload(hash_name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理拆分上传文件
|
||||||
|
fileSlice(file, hash, eachSize) {
|
||||||
|
const ext = getFileExt(file.name)
|
||||||
|
const splitNum = Math.ceil(file.size / eachSize) // 分片总数
|
||||||
|
const forms = []
|
||||||
|
|
||||||
|
// 处理每个分片的上传操作
|
||||||
|
for (let i = 0; i < splitNum; i++) {
|
||||||
|
let start = i * eachSize
|
||||||
|
let end = Math.min(file.size, start + eachSize)
|
||||||
|
|
||||||
|
// 构建表单
|
||||||
|
const form = new FormData()
|
||||||
|
form.append('file', file.slice(start, end))
|
||||||
|
form.append('name', file.name)
|
||||||
|
form.append('hash', hash)
|
||||||
|
form.append('ext', ext)
|
||||||
|
form.append('size', file.size)
|
||||||
|
form.append('split_index', i)
|
||||||
|
form.append('split_num', splitNum)
|
||||||
|
forms.push(form)
|
||||||
|
}
|
||||||
|
|
||||||
|
return forms
|
||||||
|
},
|
||||||
|
|
||||||
|
// 触发上传文件
|
||||||
|
triggerUpload(hashName) {
|
||||||
|
let $index = this.getFileIndex(hashName)
|
||||||
|
if ($index < 0 || this.items[$index].isDelte) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = this.items[$index].successNum
|
||||||
|
let form = this.items[$index].forms[i]
|
||||||
|
let length = this.items[$index].forms.length
|
||||||
|
this.items[$index].status = 1
|
||||||
|
ServeFileSubareaUpload(form)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
$index = this.getFileIndex(hashName)
|
||||||
|
this.items[$index].successNum++
|
||||||
|
this.items[$index].progress = Math.floor(
|
||||||
|
(this.items[$index].successNum / length) * 100
|
||||||
|
)
|
||||||
|
if (this.items[$index].successNum == length) {
|
||||||
|
this.items[$index].status = 2
|
||||||
|
if (res.data.is_file_merge) {
|
||||||
|
ServeSendTalkFile({
|
||||||
|
hash_name: res.data.hash,
|
||||||
|
receiver_id: this.$store.state.dialogue.receiver_id,
|
||||||
|
talk_type: this.$store.state.dialogue.talk_type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.triggerUpload(hashName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.items[$index].status = 3
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
$index = this.getFileIndex(hashName)
|
||||||
|
this.items[$index].status = 3
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取分片文件数组索引
|
||||||
|
getFileIndex(hashName) {
|
||||||
|
return this.items.findIndex(item => {
|
||||||
|
return item.hashName === hashName
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
removeFile(hashName) {
|
||||||
|
let index = this.getFileIndex(hashName)
|
||||||
|
this.items[index].isDelete = true
|
||||||
|
},
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.items = []
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.container {
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 400px;
|
||||||
|
height: 600px;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 0 5px #eae5e5;
|
||||||
|
border: 1px solid #eae5e5;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
position: relative;
|
||||||
|
text-indent: 20px;
|
||||||
|
border-bottom: 1px solid #f5eeee;
|
||||||
|
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 15px;
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mian {
|
||||||
|
.empty-data {
|
||||||
|
width: 100%;
|
||||||
|
height: 80px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 50%;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
font-size: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 30px;
|
||||||
|
color: #cccccc;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item {
|
||||||
|
width: 95%;
|
||||||
|
min-height: 100px;
|
||||||
|
background-color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 15px auto;
|
||||||
|
box-shadow: 0 0 5px #eae5e5;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.file-header {
|
||||||
|
height: 45px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
border-bottom: 1px solid #f7f4f4;
|
||||||
|
|
||||||
|
.type-icon {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
background-color: #66b1ff;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-left: 5px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 200;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filename {
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 65%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
position: absolute;
|
||||||
|
right: 14px;
|
||||||
|
top: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b6868;
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-mian {
|
||||||
|
padding: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: #f9f6f6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #ada8a8;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail {
|
||||||
|
flex: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 3px;
|
||||||
|
color: #ada8a8;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #595a5a;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-means {
|
||||||
|
width: 96.5%;
|
||||||
|
height: 35px;
|
||||||
|
border-top: 1px dashed rgb(234, 227, 227);
|
||||||
|
margin: 3px auto;
|
||||||
|
padding-top: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.btns {
|
||||||
|
width: 80px;
|
||||||
|
height: 25px;
|
||||||
|
border: 1px solid #e6e1e1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 3px;
|
||||||
|
border-radius: 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #635f5f;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
box-shadow: 0 0 5px #eae5e5;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,133 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="show" class="lum-dialog-mask animated fadeIn">
|
||||||
|
<el-container class="lum-dialog-box" v-outside="closeBox">
|
||||||
|
<el-header class="no-padding header" height="50px">
|
||||||
|
<p>发送图片</p>
|
||||||
|
<p class="tools">
|
||||||
|
<i class="el-icon-close" @click="closeBox" />
|
||||||
|
</p>
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-main class="no-padding mian">
|
||||||
|
<img v-show="src" :src="src" />
|
||||||
|
<div v-show="src">
|
||||||
|
<span class="filename">{{ fileName }}</span>
|
||||||
|
<br />
|
||||||
|
<span class="size">{{ fileSize }} KB</span>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
|
||||||
|
<el-footer class="footer" height="50px">
|
||||||
|
<el-button
|
||||||
|
class="btn"
|
||||||
|
type="primary"
|
||||||
|
size="medium"
|
||||||
|
:loading="loading"
|
||||||
|
@click="uploadImage"
|
||||||
|
>立即发送
|
||||||
|
</el-button>
|
||||||
|
</el-footer>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'MeEditorImageView',
|
||||||
|
model: {
|
||||||
|
prop: 'show',
|
||||||
|
event: 'close',
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
show: Boolean,
|
||||||
|
file: File,
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
file(file) {
|
||||||
|
this.loadFile(file)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
src: '',
|
||||||
|
fileSize: '',
|
||||||
|
fileName: '',
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeBox() {
|
||||||
|
if (this.loading) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('close', false)
|
||||||
|
},
|
||||||
|
loadFile(file) {
|
||||||
|
let reader = new FileReader()
|
||||||
|
this.fileSize = Math.ceil(file.size / 1024)
|
||||||
|
this.fileName = file.name
|
||||||
|
reader.onload = () => {
|
||||||
|
this.src = reader.result
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 确认按钮事件
|
||||||
|
uploadImage() {
|
||||||
|
this.loading = true
|
||||||
|
this.$emit('confirm')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.lum-dialog-box {
|
||||||
|
width: 500px;
|
||||||
|
max-width: 500px;
|
||||||
|
height: 450px;
|
||||||
|
|
||||||
|
.mian {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 80%;
|
||||||
|
max-height: 80%;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 0 8px #e0dbdb;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
margin-top: 10px;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 80%;
|
||||||
|
|
||||||
|
.filename {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size {
|
||||||
|
color: rgb(148, 140, 140);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
height: 50px;
|
||||||
|
background: rgba(247, 245, 245, 0.66);
|
||||||
|
text-align: center;
|
||||||
|
line-height: 50px;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 150px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,517 @@
|
||||||
|
<template>
|
||||||
|
<div class="lum-dialog-mask animated fadeIn">
|
||||||
|
<el-container class="lum-dialog-box">
|
||||||
|
<el-header class="no-padding header no-select" height="50px">
|
||||||
|
<p>语音消息</p>
|
||||||
|
<p class="tools"><i class="el-icon-close" @click="closeBox" /></p>
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-main class="no-padding mian">
|
||||||
|
<div class="music">
|
||||||
|
<span class="line line1" :class="{ 'line-ani': animation }"></span>
|
||||||
|
<span class="line line2" :class="{ 'line-ani': animation }"></span>
|
||||||
|
<span class="line line3" :class="{ 'line-ani': animation }"></span>
|
||||||
|
<span class="line line4" :class="{ 'line-ani': animation }"></span>
|
||||||
|
<span class="line line5" :class="{ 'line-ani': animation }"></span>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 35px; color: #676262; font-weight: 300">
|
||||||
|
<template v-if="recorderStatus == 0">
|
||||||
|
<p style="font-size: 13px; margin-top: 5px">
|
||||||
|
<span>语音消息,让聊天更简单方便 ...</span>
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
<template
|
||||||
|
v-else-if="
|
||||||
|
recorderStatus == 1 || recorderStatus == 2 || recorderStatus == 3
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<p>{{ datetime }}</p>
|
||||||
|
<p style="font-size: 13px; margin-top: 5px">
|
||||||
|
<span v-if="recorderStatus == 1">正在录音</span>
|
||||||
|
<span v-else-if="recorderStatus == 2">已暂停录音</span>
|
||||||
|
<span v-else-if="recorderStatus == 3">录音时长</span>
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
<template
|
||||||
|
v-else-if="
|
||||||
|
recorderStatus == 4 || recorderStatus == 5 || recorderStatus == 6
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<p>{{ formatPlayTime }}</p>
|
||||||
|
<p style="font-size: 13px; margin-top: 5px">
|
||||||
|
<span v-if="recorderStatus == 4">正在播放</span>
|
||||||
|
<span v-else-if="recorderStatus == 5">已暂停播放</span>
|
||||||
|
<span v-else-if="recorderStatus == 6">播放已结束</span>
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
|
||||||
|
<el-footer class="footer" height="50px">
|
||||||
|
<!-- 0:未开始录音 1:正在录音 2:暂停录音 3:结束录音 4:播放录音 5:停止播放 -->
|
||||||
|
<el-button
|
||||||
|
v-show="recorderStatus == 0"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
icon="el-icon-microphone"
|
||||||
|
@click="startRecorder"
|
||||||
|
>开始录音
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-show="recorderStatus == 1"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
icon="el-icon-video-pause"
|
||||||
|
@click="pauseRecorder"
|
||||||
|
>暂停录音
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-show="recorderStatus == 2"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
icon="el-icon-microphone"
|
||||||
|
@click="resumeRecorder"
|
||||||
|
>继续录音
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-show="recorderStatus == 2"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
icon="el-icon-microphone"
|
||||||
|
@click="stopRecorder"
|
||||||
|
>结束录音
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-show="recorderStatus == 3 || recorderStatus == 6"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
icon="el-icon-video-play"
|
||||||
|
@click="playRecorder"
|
||||||
|
>播放录音
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
v-show="
|
||||||
|
recorderStatus == 3 || recorderStatus == 5 || recorderStatus == 6
|
||||||
|
"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
icon="el-icon-video-play"
|
||||||
|
@click="startRecorder"
|
||||||
|
>重新录音
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
v-show="recorderStatus == 4"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
icon="el-icon-video-pause"
|
||||||
|
@click="pausePlayRecorder"
|
||||||
|
>暂停播放
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-show="recorderStatus == 5"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
icon="el-icon-video-play"
|
||||||
|
@click="resumePlayRecorder"
|
||||||
|
>继续播放
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
v-show="
|
||||||
|
recorderStatus == 3 || recorderStatus == 5 || recorderStatus == 6
|
||||||
|
"
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
@click="submit"
|
||||||
|
>立即发送
|
||||||
|
</el-button>
|
||||||
|
</el-footer>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Recorder from 'js-audio-recorder'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MeEditorRecorder',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 录音实例
|
||||||
|
recorder: null,
|
||||||
|
|
||||||
|
// 录音时长
|
||||||
|
duration: 0,
|
||||||
|
|
||||||
|
// 播放时长
|
||||||
|
playTime: 0,
|
||||||
|
|
||||||
|
animation: false,
|
||||||
|
|
||||||
|
// 当前状态
|
||||||
|
recorderStatus: 0, //0:未开始录音 1:正在录音 2:暂停录音 3:结束录音 4:播放录音 5:停止播放 6:播放结束
|
||||||
|
|
||||||
|
playTimeout: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
datetime() {
|
||||||
|
let hour = parseInt((this.duration / 60 / 60) % 24) //小时
|
||||||
|
let minute = parseInt((this.duration / 60) % 60) //分钟
|
||||||
|
let seconds = parseInt(this.duration % 60) //秒
|
||||||
|
|
||||||
|
if (hour < 10) hour = `0${hour}`
|
||||||
|
if (minute < 10) minute = `0${minute}`
|
||||||
|
if (seconds < 10) seconds = `0${seconds}`
|
||||||
|
|
||||||
|
return `${hour}:${minute}:${seconds}`
|
||||||
|
},
|
||||||
|
formatPlayTime() {
|
||||||
|
let hour = parseInt((this.playTime / 60 / 60) % 24) //小时
|
||||||
|
let minute = parseInt((this.playTime / 60) % 60) //分钟
|
||||||
|
let seconds = parseInt(this.playTime % 60) //秒
|
||||||
|
|
||||||
|
if (hour < 10) hour = `0${hour}`
|
||||||
|
if (minute < 10) minute = `0${minute}`
|
||||||
|
if (seconds < 10) seconds = `0${seconds}`
|
||||||
|
|
||||||
|
return `${hour}:${minute}:${seconds}`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
if (this.recorder) {
|
||||||
|
this.destroyRecorder()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeBox() {
|
||||||
|
if (this.recorder == null) {
|
||||||
|
this.$emit('close', false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.recorderStatus == 1) {
|
||||||
|
this.stopRecorder()
|
||||||
|
} else if (this.recorderStatus == 4) {
|
||||||
|
this.pausePlayRecorder()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁录音后关闭窗口
|
||||||
|
this.destroyRecorder(() => {
|
||||||
|
this.$emit('close', false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 开始录音
|
||||||
|
startRecorder() {
|
||||||
|
let _this = this
|
||||||
|
// http://recorder.api.zhuyuntao.cn/Recorder/event.html
|
||||||
|
// https://blog.csdn.net/qq_41619796/article/details/107865602
|
||||||
|
this.recorder = new Recorder()
|
||||||
|
this.recorder.onprocess = duration => {
|
||||||
|
duration = parseInt(duration)
|
||||||
|
_this.duration = duration
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recorder.start().then(
|
||||||
|
() => {
|
||||||
|
this.recorderStatus = 1
|
||||||
|
this.animation = true
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log(`${error.name} : ${error.message}`)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// 暂停录音
|
||||||
|
pauseRecorder() {
|
||||||
|
this.recorder.pause()
|
||||||
|
this.recorderStatus = 2
|
||||||
|
this.animation = false
|
||||||
|
},
|
||||||
|
// 继续录音
|
||||||
|
resumeRecorder() {
|
||||||
|
this.recorderStatus = 1
|
||||||
|
this.recorder.resume()
|
||||||
|
this.animation = true
|
||||||
|
},
|
||||||
|
// 结束录音
|
||||||
|
stopRecorder() {
|
||||||
|
this.recorderStatus = 3
|
||||||
|
this.recorder.stop()
|
||||||
|
this.animation = false
|
||||||
|
},
|
||||||
|
// 录音播放
|
||||||
|
playRecorder() {
|
||||||
|
this.recorderStatus = 4
|
||||||
|
this.recorder.play()
|
||||||
|
this.playTimeouts()
|
||||||
|
this.animation = true
|
||||||
|
},
|
||||||
|
// 暂停录音播放
|
||||||
|
pausePlayRecorder() {
|
||||||
|
this.recorderStatus = 5
|
||||||
|
this.recorder.pausePlay()
|
||||||
|
clearInterval(this.playTimeout)
|
||||||
|
this.animation = false
|
||||||
|
},
|
||||||
|
// 恢复录音播放
|
||||||
|
resumePlayRecorder() {
|
||||||
|
this.recorderStatus = 4
|
||||||
|
this.recorder.resumePlay()
|
||||||
|
this.playTimeouts()
|
||||||
|
this.animation = true
|
||||||
|
},
|
||||||
|
// 销毁录音
|
||||||
|
destroyRecorder(callBack) {
|
||||||
|
this.recorder.destroy().then(() => {
|
||||||
|
this.recorder = null
|
||||||
|
if (callBack) {
|
||||||
|
callBack()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取录音文件大小(单位:字节)
|
||||||
|
recorderSize() {
|
||||||
|
return this.recorder.fileSize
|
||||||
|
},
|
||||||
|
|
||||||
|
playTimeouts() {
|
||||||
|
this.playTimeout = setInterval(() => {
|
||||||
|
let time = parseInt(this.recorder.getPlayTime())
|
||||||
|
this.playTime = time
|
||||||
|
if (time == this.duration) {
|
||||||
|
clearInterval(this.playTimeout)
|
||||||
|
this.animation = false
|
||||||
|
this.recorderStatus = 6
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
alert('功能研发中,敬请期待...')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.lum-dialog-box {
|
||||||
|
width: 500px;
|
||||||
|
max-width: 500px;
|
||||||
|
height: 450px;
|
||||||
|
|
||||||
|
.mian {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 50px;
|
||||||
|
border-top: 1px solid #f7f3f3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.music {
|
||||||
|
position: relative;
|
||||||
|
width: 180px;
|
||||||
|
height: 160px;
|
||||||
|
border: 8px solid #bebebe;
|
||||||
|
border-bottom: 0px;
|
||||||
|
border-top-left-radius: 110px;
|
||||||
|
border-top-right-radius: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.music:before,
|
||||||
|
.music:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -20px;
|
||||||
|
width: 40px;
|
||||||
|
height: 82px;
|
||||||
|
background-color: #bebebe;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.music:before {
|
||||||
|
right: -25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.music:after {
|
||||||
|
left: -25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
position: absolute;
|
||||||
|
width: 6px;
|
||||||
|
min-height: 30px;
|
||||||
|
transition: 0.5s;
|
||||||
|
|
||||||
|
vertical-align: middle;
|
||||||
|
bottom: 0 !important;
|
||||||
|
box-shadow: inset 0px 0px 16px -2px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-ani {
|
||||||
|
animation: equalize 4s 0s infinite;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line1 {
|
||||||
|
left: 30%;
|
||||||
|
bottom: 0px;
|
||||||
|
animation-delay: -1.9s;
|
||||||
|
background-color: #ff5e50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line2 {
|
||||||
|
left: 40%;
|
||||||
|
height: 60px;
|
||||||
|
bottom: -15px;
|
||||||
|
animation-delay: -2.9s;
|
||||||
|
background-color: #a64de6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line3 {
|
||||||
|
left: 50%;
|
||||||
|
height: 30px;
|
||||||
|
bottom: -1.5px;
|
||||||
|
animation-delay: -3.9s;
|
||||||
|
background-color: #5968dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line4 {
|
||||||
|
left: 60%;
|
||||||
|
height: 65px;
|
||||||
|
bottom: -16px;
|
||||||
|
animation-delay: -4.9s;
|
||||||
|
background-color: #27c8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line5 {
|
||||||
|
left: 70%;
|
||||||
|
height: 60px;
|
||||||
|
bottom: -12px;
|
||||||
|
animation-delay: -5.9s;
|
||||||
|
background-color: #cc60b5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes equalize {
|
||||||
|
0% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
4% {
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
8% {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
12% {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
16% {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
24% {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
28% {
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
32% {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
36% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
44% {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
48% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
52% {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
56% {
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
64% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
68% {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
72% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
76% {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
84% {
|
||||||
|
height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
88% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
92% {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
96% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,169 @@
|
||||||
|
<template>
|
||||||
|
<div class="lum-dialog-mask">
|
||||||
|
<el-container class="lum-dialog-box" v-outside="closeBox">
|
||||||
|
<el-header class="no-padding header" height="50px">
|
||||||
|
<p>系统表情</p>
|
||||||
|
<p class="tools">
|
||||||
|
<i class="el-icon-close" @click="closeBox" />
|
||||||
|
</p>
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-main class="no-padding mian lum-scrollbar">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(item, i) in items" :key="item.id" class="no-select">
|
||||||
|
<div class="pkg-avatar">
|
||||||
|
<el-image :src="item.icon" fit="cover" :lazy="true" />
|
||||||
|
</div>
|
||||||
|
<div class="pkg-info" v-text="item.name"></div>
|
||||||
|
<div class="pkg-status">
|
||||||
|
<button
|
||||||
|
:class="{
|
||||||
|
'add-emoji': item.status == 0,
|
||||||
|
'remove-emoji': item.status != 0,
|
||||||
|
}"
|
||||||
|
@click="setEmoticon(i, item, item.status == 0 ? 1 : 2)"
|
||||||
|
>
|
||||||
|
{{ item.status == 0 ? '添加' : '移除' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</el-main>
|
||||||
|
|
||||||
|
<el-footer class="footer" height="50px">
|
||||||
|
<el-button type="primary" size="medium" class="btn" @click="closeBox">
|
||||||
|
关闭窗口
|
||||||
|
</el-button>
|
||||||
|
</el-footer>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ServeFindSysEmoticon, ServeSetUserEmoticon } from '@/api/emoticon'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MeEditorSystemEmoticon',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
items: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadSysEmoticon()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeBox() {
|
||||||
|
this.$emit('close')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取系统表情包列表
|
||||||
|
loadSysEmoticon() {
|
||||||
|
ServeFindSysEmoticon().then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.items = res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
setEmoticon(index, item, type) {
|
||||||
|
ServeSetUserEmoticon({
|
||||||
|
emoticon_id: item.id,
|
||||||
|
type: type,
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
if (type == 1) {
|
||||||
|
this.items[index].status = 1
|
||||||
|
this.$store.commit('APPEND_SYS_EMOTICON', res.data)
|
||||||
|
} else {
|
||||||
|
this.items[index].status = 0
|
||||||
|
this.$store.commit('REMOVE_SYS_EMOTICON', {
|
||||||
|
emoticon_id: item.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.lum-dialog-box {
|
||||||
|
width: 350px;
|
||||||
|
max-width: 350px;
|
||||||
|
height: 500px;
|
||||||
|
|
||||||
|
.mian {
|
||||||
|
height: 480px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 68px;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 3px solid #fbf2fb;
|
||||||
|
padding-left: 5px;
|
||||||
|
|
||||||
|
.pkg-avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pkg-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
margin-left: 14px;
|
||||||
|
margin-right: 14px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
width: 200px;
|
||||||
|
color: #615d5d;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pkg-status {
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 28px;
|
||||||
|
border-radius: 20px;
|
||||||
|
width: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-emoji {
|
||||||
|
background-color: #38adff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-emoji {
|
||||||
|
background-color: #ff5722;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
height: 50px;
|
||||||
|
background: rgba(247, 245, 245, 0.66);
|
||||||
|
text-align: center;
|
||||||
|
line-height: 50px;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 150px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,226 @@
|
||||||
|
<template>
|
||||||
|
<div class="lum-dialog-mask animated fadeIn">
|
||||||
|
<el-container class="lum-dialog-box">
|
||||||
|
<el-header class="header no-select" height="60px">
|
||||||
|
<p>发起投票</p>
|
||||||
|
<p class="tools">
|
||||||
|
<i class="el-icon-close" @click="$emit('close')" />
|
||||||
|
</p>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="main no-padding vote-from">
|
||||||
|
<div class="vote-title">投票方式</div>
|
||||||
|
<div>
|
||||||
|
<el-radio-group v-model="mode">
|
||||||
|
<el-radio :label="0">单选</el-radio>
|
||||||
|
<el-radio :label="1">多选</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
<div class="vote-title">投票主题</div>
|
||||||
|
<div>
|
||||||
|
<el-input
|
||||||
|
size="medium"
|
||||||
|
clear="vote-input"
|
||||||
|
v-model.trim="title"
|
||||||
|
placeholder="请输入投票主题,最多50字"
|
||||||
|
:maxlength="50"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="vote-title">投票选项</div>
|
||||||
|
<div>
|
||||||
|
<div class="vote-options" v-for="(option, index) in options">
|
||||||
|
<div class="lbox">
|
||||||
|
<el-input
|
||||||
|
size="medium"
|
||||||
|
clear="vote-input"
|
||||||
|
v-model.trim="option.value"
|
||||||
|
placeholder="请输入选项内容"
|
||||||
|
:maxlength="120"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
slot="prefix"
|
||||||
|
style="margin-left:7px;"
|
||||||
|
v-text="String.fromCharCode(65 + index)"
|
||||||
|
/>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
<div class="rbox">
|
||||||
|
<i class="el-icon-close" @click="removeOption(index)"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h6 class="pointer add-option" @click="addOption">
|
||||||
|
<i class="el-icon-plus"></i> 添加选项
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
<el-footer class="footer">
|
||||||
|
<el-button plain size="small">取消</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
:disabled="isCheck"
|
||||||
|
:loading="loading"
|
||||||
|
@click="submit"
|
||||||
|
>发起投票</el-button
|
||||||
|
>
|
||||||
|
</el-footer>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { ServeSendVote } from '@/api/chat'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MeEditorVote',
|
||||||
|
props: {
|
||||||
|
group_id: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
mode: 0,
|
||||||
|
title: '',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isCheck() {
|
||||||
|
if (this.title == '') return true
|
||||||
|
|
||||||
|
return this.options.some(option => option.value == '')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit() {
|
||||||
|
let items = []
|
||||||
|
const { receiver_id } = this.$store.state.dialogue
|
||||||
|
this.options.forEach(option => {
|
||||||
|
items.push(option.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
|
||||||
|
ServeSendVote({
|
||||||
|
receiver_id,
|
||||||
|
mode: this.mode,
|
||||||
|
title: this.title,
|
||||||
|
options: items,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.$emit('close')
|
||||||
|
this.$notify({
|
||||||
|
title: '友情提示',
|
||||||
|
message: '发起投票成功!',
|
||||||
|
type: 'success',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$notify({
|
||||||
|
title: '友情提示',
|
||||||
|
message: res.message,
|
||||||
|
type: 'warning',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addOption() {
|
||||||
|
if (this.options.length >= 6) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options.push({
|
||||||
|
value: '',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removeOption(index) {
|
||||||
|
if (this.options.length <= 2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$delete(this.options, index)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.lum-dialog-box {
|
||||||
|
height: 600px;
|
||||||
|
max-width: 450px;
|
||||||
|
|
||||||
|
.vote-from {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 15px 25px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.vote-title {
|
||||||
|
margin: 20px 0 10px;
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-options {
|
||||||
|
display: flex;
|
||||||
|
min-height: 30px;
|
||||||
|
margin: 10px 0;
|
||||||
|
|
||||||
|
.lbox {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
/deep/.el-input__prefix {
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbox {
|
||||||
|
flex-basis: 50px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
i {
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-option {
|
||||||
|
margin-top: 5px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #3370ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-right: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/.el-radio__input.is-checked + .el-radio__label {
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<template>
|
||||||
|
<img :src="'https://avatars.dicebear.com/api/initials/'+text+'.svg?fontSize=38'" alt=""/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props:{
|
||||||
|
text:{
|
||||||
|
type:null,
|
||||||
|
default:''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<template>
|
||||||
|
<img :src="text" alt=""/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props:{
|
||||||
|
text:{
|
||||||
|
type:null,
|
||||||
|
default:''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<div class="empty-content">
|
||||||
|
<div class="image">
|
||||||
|
<img :src="src" />
|
||||||
|
</div>
|
||||||
|
<div class="text" v-text="text" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Empty',
|
||||||
|
props: {
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: '数据为空...',
|
||||||
|
},
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: require('@/assets/image/no-oncall.6b776fcf.png'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.empty-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 60%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,313 @@
|
||||||
|
<template>
|
||||||
|
<div class="loading-content">
|
||||||
|
<div class="ant-spin ant-spin-lg ant-spin-spinning">
|
||||||
|
<span class="ant-spin-dot ant-spin-dot-spin">
|
||||||
|
<i class="ant-spin-dot-item" />
|
||||||
|
<i class="ant-spin-dot-item" />
|
||||||
|
<i class="ant-spin-dot-item" />
|
||||||
|
<i class="ant-spin-dot-item" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p>{{ text }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Loading',
|
||||||
|
props: {
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: '数据加载中 ...',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.loading-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 60%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 13px;
|
||||||
|
p {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ant-spin 加载动画 start */
|
||||||
|
.ant-spin {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
font-size: 14px;
|
||||||
|
font-variant: tabular-nums;
|
||||||
|
line-height: 1.5715;
|
||||||
|
list-style: none;
|
||||||
|
-webkit-font-feature-settings: 'tnum';
|
||||||
|
font-feature-settings: 'tnum';
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
color: #1890ff;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transition: -webkit-transform 0.3s
|
||||||
|
cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||||
|
transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||||
|
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||||
|
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
|
||||||
|
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-spinning {
|
||||||
|
position: static;
|
||||||
|
display: inline-block;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 4;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
margin: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin .ant-spin-text {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 5px;
|
||||||
|
text-shadow: 0 1px 2px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin.ant-spin-show-text .ant-spin-dot {
|
||||||
|
margin-top: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin-sm .ant-spin-dot {
|
||||||
|
margin: -7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin-sm .ant-spin-text {
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin-sm.ant-spin-show-text .ant-spin-dot {
|
||||||
|
margin-top: -17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin-lg .ant-spin-dot {
|
||||||
|
margin: -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin-lg .ant-spin-text {
|
||||||
|
padding-top: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-nested-loading > div > .ant-spin-lg.ant-spin-show-text .ant-spin-dot {
|
||||||
|
margin-top: -26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-container {
|
||||||
|
position: relative;
|
||||||
|
-webkit-transition: opacity 0.3s;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-container::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
display: none \9;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transition: all 0.3s;
|
||||||
|
transition: all 0.3s;
|
||||||
|
content: '';
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-blur {
|
||||||
|
clear: both;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 0.5;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-blur::after {
|
||||||
|
opacity: 0.4;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-tip {
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-dot {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 20px;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-dot-item {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
background-color: #1890ff;
|
||||||
|
border-radius: 100%;
|
||||||
|
-webkit-transform: scale(0.75);
|
||||||
|
transform: scale(0.75);
|
||||||
|
-webkit-transform-origin: 50% 50%;
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
opacity: 0.3;
|
||||||
|
-webkit-animation: antSpinMove 1s infinite linear alternate;
|
||||||
|
animation: antSpinMove 1s infinite linear alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-dot-item:nth-child(1) {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-dot-item:nth-child(2) {
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
-webkit-animation-delay: 0.4s;
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-dot-item:nth-child(3) {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
-webkit-animation-delay: 0.8s;
|
||||||
|
animation-delay: 0.8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-dot-item:nth-child(4) {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
-webkit-animation-delay: 1.2s;
|
||||||
|
animation-delay: 1.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-dot-spin {
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
-webkit-animation: antRotate 1.2s infinite linear;
|
||||||
|
animation: antRotate 1.2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-sm .ant-spin-dot {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-sm .ant-spin-dot i {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-lg .ant-spin-dot {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-lg .ant-spin-dot i {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin.ant-spin-show-text .ant-spin-text {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
||||||
|
.ant-spin-blur {
|
||||||
|
background: #fff;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes antSpinMove {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes antSpinMove {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes antRotate {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(405deg);
|
||||||
|
transform: rotate(405deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes antRotate {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(405deg);
|
||||||
|
transform: rotate(405deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-spin-rtl .ant-spin-dot-spin {
|
||||||
|
-webkit-transform: rotate(-45deg);
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
-webkit-animation-name: antRotateRtl;
|
||||||
|
animation-name: antRotateRtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes antRotateRtl {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(-405deg);
|
||||||
|
transform: rotate(-405deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes antRotateRtl {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(-405deg);
|
||||||
|
transform: rotate(-405deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ant-spin 加载动画 end */
|
||||||
|
</style>
|
|
@ -0,0 +1,80 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="abs-module" v-show="isShow">
|
||||||
|
<div class="abs-box">
|
||||||
|
<i class="el-icon-circle-close" @click="close" />
|
||||||
|
<a href="https://www.aliyun.com/minisite/goods?userCode=kqyyppx2">
|
||||||
|
<img src="~@/assets/image/aliyun-abs.jpg" width="300" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isShow: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.getNum() <= 2) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isShow = true
|
||||||
|
}, 1000 * 60 * 2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getNum() {
|
||||||
|
return parseInt(sessionStorage.getItem('ABS_BOX')) || 0
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
sessionStorage.setItem('ABS_BOX', this.getNum() + 1)
|
||||||
|
this.isShow = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.abs-module {
|
||||||
|
position: fixed;
|
||||||
|
width: 300px;
|
||||||
|
height: 163.63px;
|
||||||
|
right: 20px;
|
||||||
|
top: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 9999;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 2s;
|
||||||
|
animation: absfade 1000ms infinite;
|
||||||
|
|
||||||
|
.abs-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes absfade {
|
||||||
|
from {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,246 @@
|
||||||
|
<template>
|
||||||
|
<div class="lum-dialog-mask">
|
||||||
|
<el-container class="lum-dialog-box">
|
||||||
|
<el-header class="header" height="50px">
|
||||||
|
<p>选择头像</p>
|
||||||
|
<p class="tools">
|
||||||
|
<i class="el-icon-close" @click="$emit('close', 0)" />
|
||||||
|
</p>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="main">
|
||||||
|
<el-container class="full-height">
|
||||||
|
<el-aside width="400px">
|
||||||
|
<div class="cropper-box">
|
||||||
|
<vue-cropper
|
||||||
|
ref="cropper"
|
||||||
|
mode="cover"
|
||||||
|
:img="option.img"
|
||||||
|
:output-size="option.size"
|
||||||
|
:output-type="option.outputType"
|
||||||
|
:info="true"
|
||||||
|
:full="option.full"
|
||||||
|
:fixed="fixed"
|
||||||
|
:fixed-number="fixedNumber"
|
||||||
|
:can-move="option.canMove"
|
||||||
|
:can-move-box="option.canMoveBox"
|
||||||
|
:fixed-box="option.fixedBox"
|
||||||
|
:original="option.original"
|
||||||
|
:auto-crop="option.autoCrop"
|
||||||
|
:auto-crop-width="option.autoCropWidth"
|
||||||
|
:auto-crop-height="option.autoCropHeight"
|
||||||
|
:center-box="option.centerBox"
|
||||||
|
:high="option.high"
|
||||||
|
@real-time="realTime"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="uploads"
|
||||||
|
ref="fileInput"
|
||||||
|
accept="image/png, image/jpeg, image/jpg"
|
||||||
|
style="display: none"
|
||||||
|
@change="uploadImg($event, 1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="tools tools-flex">
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
icon="el-icon-upload"
|
||||||
|
@click="clickUpload"
|
||||||
|
>上传图片
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
icon="el-icon-refresh"
|
||||||
|
@click="refreshCrop"
|
||||||
|
>刷新
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
icon="el-icon-refresh-left"
|
||||||
|
@click="rotateLeft"
|
||||||
|
>左转
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
icon="el-icon-refresh-right"
|
||||||
|
@click="rotateRight"
|
||||||
|
>右转
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-aside>
|
||||||
|
<el-main class="no-padding">
|
||||||
|
<div class="cropper-box">
|
||||||
|
<div class="preview-img">
|
||||||
|
<img v-if="cusPreviewsImg" :src="cusPreviewsImg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tools">
|
||||||
|
<el-button type="primary" size="small" @click="uploadService">
|
||||||
|
保存图片
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { VueCropper } from 'vue-cropper'
|
||||||
|
import { ServeUploadFileStream } from '@/api/upload'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AvatarCropper',
|
||||||
|
components: {
|
||||||
|
VueCropper,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
cusPreviewsImg: '',
|
||||||
|
previews: {},
|
||||||
|
option: {
|
||||||
|
img: '',
|
||||||
|
size: 1,
|
||||||
|
full: false,
|
||||||
|
outputType: 'png',
|
||||||
|
canMove: true,
|
||||||
|
fixedBox: true,
|
||||||
|
original: false,
|
||||||
|
canMoveBox: true,
|
||||||
|
autoCrop: true,
|
||||||
|
// 只有自动截图开启 宽度高度才生效
|
||||||
|
autoCropWidth: 200,
|
||||||
|
autoCropHeight: 150,
|
||||||
|
centerBox: false,
|
||||||
|
high: true,
|
||||||
|
},
|
||||||
|
fixed: true,
|
||||||
|
fixedNumber: [1, 1],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickUpload() {
|
||||||
|
this.$refs.fileInput.click()
|
||||||
|
},
|
||||||
|
clearCrop() {
|
||||||
|
if (!this.cusPreviewsImg) return false
|
||||||
|
this.$refs.cropper.clearCrop()
|
||||||
|
},
|
||||||
|
refreshCrop() {
|
||||||
|
if (!this.cusPreviewsImg) return false
|
||||||
|
this.$refs.cropper.refresh()
|
||||||
|
},
|
||||||
|
rotateLeft() {
|
||||||
|
if (!this.cusPreviewsImg) return false
|
||||||
|
this.$refs.cropper.rotateLeft()
|
||||||
|
},
|
||||||
|
rotateRight() {
|
||||||
|
if (!this.cusPreviewsImg) return false
|
||||||
|
this.$refs.cropper.rotateRight()
|
||||||
|
},
|
||||||
|
// 实时预览函数
|
||||||
|
realTime() {
|
||||||
|
this.$refs.cropper.getCropData(img => {
|
||||||
|
this.cusPreviewsImg = img
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传回调事件
|
||||||
|
uploadImg(e, num) {
|
||||||
|
let file = e.target.files[0]
|
||||||
|
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
|
||||||
|
this.$message('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let reader = new FileReader()
|
||||||
|
reader.onload = e => {
|
||||||
|
let data
|
||||||
|
if (typeof e.target.result === 'object') {
|
||||||
|
// 把Array Buffer转化为blob 如果是base64不需要
|
||||||
|
data = window.URL.createObjectURL(new Blob([e.target.result]))
|
||||||
|
} else {
|
||||||
|
data = e.target.result
|
||||||
|
}
|
||||||
|
if (num === 1) {
|
||||||
|
this.option.img = data
|
||||||
|
} else if (num === 2) {
|
||||||
|
this.example2.img = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 转化为base64
|
||||||
|
// reader.readAsDataURL(file)
|
||||||
|
// 转化为blob
|
||||||
|
reader.readAsArrayBuffer(file)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传图片到服务器
|
||||||
|
uploadService() {
|
||||||
|
if (this.cusPreviewsImg == '') return
|
||||||
|
ServeUploadFileStream({
|
||||||
|
fileStream: this.cusPreviewsImg,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.$emit('close', 1, res.data.avatar)
|
||||||
|
} else {
|
||||||
|
this.$message('文件上传失败,请稍后再试...')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$message('文件上传失败,请稍后再试...')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.lum-dialog-box {
|
||||||
|
height: 550px;
|
||||||
|
max-width: 800px;
|
||||||
|
|
||||||
|
.main {
|
||||||
|
.cropper-box {
|
||||||
|
height: 400px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.preview-img {
|
||||||
|
width: 180px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 0 4px #ccc;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
height: 40px;
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,129 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="reward" v-show="isShow">
|
||||||
|
<div class="title">
|
||||||
|
<span>Donate</span>
|
||||||
|
<i class="el-icon-circle-close" @click="close" />
|
||||||
|
</div>
|
||||||
|
<div class="main">
|
||||||
|
<div class="pay-box">
|
||||||
|
<img
|
||||||
|
src="https://cdn.learnku.com/uploads/images/202101/30/46424/PPYHOUhCb4.jpg"
|
||||||
|
/>
|
||||||
|
<p>支付宝</p>
|
||||||
|
</div>
|
||||||
|
<div class="pay-box">
|
||||||
|
<img
|
||||||
|
src="https://cdn.learnku.com/uploads/images/202101/30/46424/XLmCJjbvlQ.png"
|
||||||
|
/>
|
||||||
|
<p>微信</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
开源不易,如果你觉得项目对你有帮助,可以请作者喝杯咖啡☕️!鼓励下...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isShow: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.getNum() <= 3) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isShow = true
|
||||||
|
}, 1000 * 30)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getNum() {
|
||||||
|
return parseInt(localStorage.getItem('REWARD_BOX')) || 0
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
localStorage.setItem('REWARD_BOX', this.getNum() + 1)
|
||||||
|
this.isShow = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.reward {
|
||||||
|
position: fixed;
|
||||||
|
width: 550px;
|
||||||
|
height: 400px;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 12px #ccc;
|
||||||
|
border: 1px solid rgb(228, 225, 225);
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 9999;
|
||||||
|
background: white;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
padding-left: 20px;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
background: #f9f7f7;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
right: 15px;
|
||||||
|
top: 18px;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
height: 300px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.pay-box {
|
||||||
|
width: 200px;
|
||||||
|
height: 240px;
|
||||||
|
background: #1977ff;
|
||||||
|
margin: 0 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 20px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
background: #22ab38;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 待开发
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
skins: [
|
||||||
|
{
|
||||||
|
theme: '',
|
||||||
|
class: 'default',
|
||||||
|
text: '默认',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
theme: '',
|
||||||
|
class: 'red',
|
||||||
|
text: '红色',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
theme: '',
|
||||||
|
class: 'dark',
|
||||||
|
text: '暗黑',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
theme: '',
|
||||||
|
class: 'blue',
|
||||||
|
text: '浅蓝',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped></style>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<template>
|
||||||
|
<div class="welcome-box">
|
||||||
|
<div class="famous-box">
|
||||||
|
<img src="~@/assets/image/chat.png" width="300" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.welcome-box {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.famous-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 24px;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
p {
|
||||||
|
width: 100%;
|
||||||
|
font-weight: 300;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #b9b4b4;
|
||||||
|
margin-top: -30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,103 @@
|
||||||
|
<template>
|
||||||
|
<!-- 新消息提示组件 -->
|
||||||
|
<div class="notify-box">
|
||||||
|
<div class="lbox">
|
||||||
|
<el-avatar size="medium" :src="avatar" />
|
||||||
|
</div>
|
||||||
|
<div class="rbox">
|
||||||
|
<div class="xheader">
|
||||||
|
<p class="title">好友申请消息</p>
|
||||||
|
<p class="time">{{ datetime }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="xbody">
|
||||||
|
<h4>申请备注:</h4>
|
||||||
|
<div>{{ content }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
components: {},
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
default() {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
avatar:
|
||||||
|
'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
|
||||||
|
talk_type: 1,
|
||||||
|
nickname: '阿萨纳斯卡',
|
||||||
|
content: '阿斯纳俺家你卡萨啊看看番按实际开发n',
|
||||||
|
datetime: '2021-06-18 23:15:12',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
methods: {},
|
||||||
|
created() {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.notify-box {
|
||||||
|
width: 300px;
|
||||||
|
min-height: 100px;
|
||||||
|
// background: rebeccapurple;
|
||||||
|
display: flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
.lbox {
|
||||||
|
flex-basis: 50px;
|
||||||
|
flex-shrink: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbox {
|
||||||
|
flex: 1 auto;
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
.xheader {
|
||||||
|
height: 35px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.time {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.xbody {
|
||||||
|
min-height: 60px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #f3f5f7;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,122 @@
|
||||||
|
<template>
|
||||||
|
<!-- 新消息提示组件 -->
|
||||||
|
<div class="notify-box pointer">
|
||||||
|
<div class="lbox">
|
||||||
|
<el-avatar size="medium" shape="square" :src="avatar" />
|
||||||
|
</div>
|
||||||
|
<div class="rbox">
|
||||||
|
<div class="xheader">
|
||||||
|
<p class="title">
|
||||||
|
{{ talk_type == 1 ? '私信消息通知' : '群聊消息通知' }}
|
||||||
|
</p>
|
||||||
|
<p class="time"><i class="el-icon-time" /> {{ datetime | format }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="xbody">
|
||||||
|
<p>@{{ nickname }}</p>
|
||||||
|
<div>{{ content }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { parseTime } from '@/utils/functions'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {},
|
||||||
|
props: {
|
||||||
|
avatar: {
|
||||||
|
type: String,
|
||||||
|
default:
|
||||||
|
'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
|
||||||
|
},
|
||||||
|
talk_type: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
nickname: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
datetime: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
format(datetime) {
|
||||||
|
datetime = datetime || new Date()
|
||||||
|
return parseTime(datetime, '{m}/{d} {h}:{i} 分')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.notify-box {
|
||||||
|
width: 300px;
|
||||||
|
min-height: 100px;
|
||||||
|
display: flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
.lbox {
|
||||||
|
flex-basis: 50px;
|
||||||
|
flex-shrink: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbox {
|
||||||
|
flex: 1 auto;
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
.xheader {
|
||||||
|
height: 25px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.time {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.xbody {
|
||||||
|
min-height: 60px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 5px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #fb4208;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #f3f5f7;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<svg :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||||
|
<use :xlink:href="iconName" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'svg-icon',
|
||||||
|
props: {
|
||||||
|
iconClass: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iconName() {
|
||||||
|
return `#icon-${this.iconClass}`
|
||||||
|
},
|
||||||
|
svgClass() {
|
||||||
|
if (this.className) {
|
||||||
|
return 'svg-icon ' + this.className
|
||||||
|
} else {
|
||||||
|
return 'svg-icon'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.svg-icon {
|
||||||
|
fill: currentColor;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,119 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="lum-dialog-mask" v-show="isShow">
|
||||||
|
<el-container class="lum-dialog-box" v-outside="close">
|
||||||
|
<el-header class="header" height="50px">
|
||||||
|
<p>添加好友</p>
|
||||||
|
<p class="tools">
|
||||||
|
<i class="el-icon-close" @click="close" />
|
||||||
|
</p>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="main">
|
||||||
|
<el-input
|
||||||
|
v-model="mobile"
|
||||||
|
id="serach-mobile"
|
||||||
|
class="input"
|
||||||
|
prefix-icon="el-icon-search"
|
||||||
|
placeholder="请输入对方手机号(精确查找)"
|
||||||
|
clearable
|
||||||
|
@keyup.enter.native="onSubmit"
|
||||||
|
@input="error = false"
|
||||||
|
/>
|
||||||
|
<p v-show="error" class="error">
|
||||||
|
无法找到该用户,请检查搜索内容并重试
|
||||||
|
</p>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
:loading="loading"
|
||||||
|
@click="onSubmit"
|
||||||
|
>立即查找
|
||||||
|
</el-button>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { ServeSearchContact } from '@/api/contacts'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UserSearch',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
isShow: false,
|
||||||
|
mobile: '',
|
||||||
|
error: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 显示窗口
|
||||||
|
open() {
|
||||||
|
this.mobile = ''
|
||||||
|
this.isShow = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
document.getElementById('serach-mobile').focus()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 关闭窗口
|
||||||
|
close() {
|
||||||
|
this.isShow = false
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
let { mobile } = this
|
||||||
|
|
||||||
|
if (mobile == '') return false
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
ServeSearchContact({
|
||||||
|
mobile,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.$user(res.data.id)
|
||||||
|
this.close()
|
||||||
|
} else {
|
||||||
|
this.error = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.lum-dialog-box {
|
||||||
|
width: 450px;
|
||||||
|
max-width: 450px;
|
||||||
|
height: 250px;
|
||||||
|
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
width: 85%;
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,483 @@
|
||||||
|
<template>
|
||||||
|
<div class="lum-dialog-mask animated fadeIn">
|
||||||
|
<el-container class="container" v-outside="close">
|
||||||
|
<el-header class="no-padding header" height="180px">
|
||||||
|
<i class="close el-icon-error pointer" @click="close" />
|
||||||
|
<div class="img-banner">
|
||||||
|
<img :src="detail.bag" class="img-banner" />
|
||||||
|
</div>
|
||||||
|
<div class="user-header">
|
||||||
|
<div class="avatar">
|
||||||
|
<div class="avatar-box">
|
||||||
|
<img :src="detail.avatar" :onerror="$store.state.defaultAvatar" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nickname">
|
||||||
|
<i class="iconfont icon-qianming" />
|
||||||
|
<span>{{ detail.nickname || "未设置昵称" }}</span>
|
||||||
|
<div class="share no-select">
|
||||||
|
<i class="iconfont icon-fenxiang3" /> <span>分享</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="no-padding main">
|
||||||
|
<div class="user-sign">
|
||||||
|
<div class="sign-arrow"></div>
|
||||||
|
<i class="iconfont icon-bianji" />
|
||||||
|
<span>编辑个签,展示我的独特态度。 </span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-rows no-select">
|
||||||
|
<div class="card-row">
|
||||||
|
<label>手机</label>
|
||||||
|
<span>{{ detail.mobile | mobile }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-row">
|
||||||
|
<label>昵称</label>
|
||||||
|
<span>{{ detail.nickname || "未设置昵称" }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-row">
|
||||||
|
<label>性别</label>
|
||||||
|
<span>{{ detail.gender | gender }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-show="detail.friend_status == 2" class="card-row">
|
||||||
|
<label>备注</label>
|
||||||
|
<span v-if="editRemark.isShow == false">{{
|
||||||
|
detail.nickname_remark ? detail.nickname_remark : "暂无备注"
|
||||||
|
}}</span>
|
||||||
|
<span v-else>
|
||||||
|
<input
|
||||||
|
v-model="editRemark.text"
|
||||||
|
v-focus
|
||||||
|
class="friend-remark"
|
||||||
|
type="text"
|
||||||
|
@keyup.enter="editRemarkSubmit"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<i
|
||||||
|
v-show="!editRemark.isShow"
|
||||||
|
class="el-icon-edit-outline"
|
||||||
|
@click="clickEditRemark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="card-row">
|
||||||
|
<label>邮箱</label>
|
||||||
|
<span>未设置</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
<el-footer
|
||||||
|
v-show="detail.friend_status !== 0"
|
||||||
|
class="no-padding footer"
|
||||||
|
height="50px"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-if="detail.friend_status == 1 && detail.friend_apply == 0"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-circle-plus-outline"
|
||||||
|
@click="apply.isShow = true"
|
||||||
|
>添加好友
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-else-if="detail.friend_apply == 1"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
>已发送好友申请,请耐心等待...
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-else-if="detail.friend_status == 2"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-s-promotion"
|
||||||
|
@click="sendMessage(detail)"
|
||||||
|
>发消息
|
||||||
|
</el-button>
|
||||||
|
</el-footer>
|
||||||
|
|
||||||
|
<!-- 添加好友申请表单 -->
|
||||||
|
<div
|
||||||
|
v-outside="closeApply"
|
||||||
|
class="friend-from"
|
||||||
|
:class="{ 'friend-from-show': apply.isShow }"
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
<span>请填写好友申请备注:</span>
|
||||||
|
<span @click="closeApply">取消</span>
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
v-model="apply.text"
|
||||||
|
type="text"
|
||||||
|
placeholder="(必填项)"
|
||||||
|
@keyup.enter="sendApply"
|
||||||
|
/>
|
||||||
|
<el-button type="primary" size="small" @click="sendApply">
|
||||||
|
立即提交
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
// import { ServeSearchUser } from "@/api/user";
|
||||||
|
import { ServeCreateContact, ServeEditContactRemark } from "@/api/contacts";
|
||||||
|
import { toTalk } from "@/utils/talk";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "UserCardDetail",
|
||||||
|
props: {
|
||||||
|
user_id: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
gender(value) {
|
||||||
|
let arr = ["未知", "男", "女"];
|
||||||
|
return arr[value] || "未知";
|
||||||
|
},
|
||||||
|
// 手机号格式化
|
||||||
|
mobile(value) {
|
||||||
|
return (
|
||||||
|
value.substr(0, 3) + " " + value.substr(3, 4) + " " + value.substr(7, 4)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
detail: {
|
||||||
|
mobile: "",
|
||||||
|
nickname: "",
|
||||||
|
avatar: "",
|
||||||
|
motto: "",
|
||||||
|
friend_status: 0,
|
||||||
|
friend_apply: 0,
|
||||||
|
nickname_remark: "",
|
||||||
|
bag: require("@/assets/image/default-user-banner.png"),
|
||||||
|
gender: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 好友备注表单
|
||||||
|
editRemark: {
|
||||||
|
isShow: false,
|
||||||
|
text: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
// 好友申请表单
|
||||||
|
apply: {
|
||||||
|
isShow: false,
|
||||||
|
text: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
contacts: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// this.loadUserDetail();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close() {
|
||||||
|
if (this.contacts) return false;
|
||||||
|
|
||||||
|
this.$emit("close");
|
||||||
|
},
|
||||||
|
|
||||||
|
// 点击编辑备注信息
|
||||||
|
clickEditRemark() {
|
||||||
|
this.editRemark.isShow = true;
|
||||||
|
this.editRemark.text = this.detail.nickname_remark;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
// loadUserDetail() {
|
||||||
|
// ServeSearchUser({
|
||||||
|
// user_id: this.user_id,
|
||||||
|
// }).then((res) => {
|
||||||
|
// if (res.code == 200) {
|
||||||
|
// this.detail.user_id = res.data.id;
|
||||||
|
// Object.assign(this.detail, res.data);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
|
||||||
|
// 发送添加好友申请
|
||||||
|
sendApply() {
|
||||||
|
if (this.apply.text == "") return;
|
||||||
|
ServeCreateContact({
|
||||||
|
friend_id: this.detail.user_id,
|
||||||
|
remark: this.apply.text,
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.apply.isShow = false;
|
||||||
|
this.apply.text = "";
|
||||||
|
this.detail.friend_apply = 1;
|
||||||
|
} else {
|
||||||
|
this.$message.error("发送好友申请失败,请稍后再试...");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 编辑好友备注信息
|
||||||
|
editRemarkSubmit() {
|
||||||
|
let data = {
|
||||||
|
friend_id: this.detail.user_id,
|
||||||
|
remarks: this.editRemark.text,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data.remarks == this.detail.nickname_remark) {
|
||||||
|
this.editRemark.isShow = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServeEditContactRemark(data).then((res) => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.editRemark.isShow = false;
|
||||||
|
this.detail.nickname_remark = data.remarks;
|
||||||
|
this.$emit("changeRemark", data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 隐藏申请表单
|
||||||
|
closeApply() {
|
||||||
|
this.apply.isShow = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 发送好友消息
|
||||||
|
sendMessage() {
|
||||||
|
this.close();
|
||||||
|
toTalk(1, this.user_id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.container {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: white;
|
||||||
|
width: 350px;
|
||||||
|
height: 600px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
color: white;
|
||||||
|
transition: all 1s;
|
||||||
|
z-index: 1;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-banner {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-image: url(~@/assets/image/default-user-banner.png);
|
||||||
|
background-size: 100%;
|
||||||
|
transition: all 0.2s linear;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
img:hover {
|
||||||
|
-webkit-transform: scale(1.1);
|
||||||
|
transform: scale(1.1);
|
||||||
|
-webkit-filter: contrast(130%);
|
||||||
|
filter: contrast(130%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
background-color: white;
|
||||||
|
padding: 45px 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-top: 1px solid #f5eeee;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-header {
|
||||||
|
width: 100%;
|
||||||
|
height: 80px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 100px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.avatar-box {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 70px;
|
||||||
|
width: 70px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname {
|
||||||
|
flex: auto;
|
||||||
|
padding-top: 50px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share {
|
||||||
|
display: inline-flex;
|
||||||
|
width: 50px;
|
||||||
|
height: 22px;
|
||||||
|
background: #ff5722;
|
||||||
|
color: white;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 3px 8px;
|
||||||
|
border-radius: 20px;
|
||||||
|
transform: scale(0.7);
|
||||||
|
cursor: pointer;
|
||||||
|
i {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-sign {
|
||||||
|
min-height: 26px;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
line-height: 25px;
|
||||||
|
background: #f3f5f7;
|
||||||
|
color: #7d7d7d;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.sign-arrow {
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
font-size: 0;
|
||||||
|
border: 5px solid hsla(0, 0%, 96.9%, 0);
|
||||||
|
border-bottom-color: #f3f5f7;
|
||||||
|
left: 28px;
|
||||||
|
top: -9px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-rows {
|
||||||
|
.card-row {
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
font-size: 14px;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #736f6f;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-right: 25px;
|
||||||
|
color: #cbc5c5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.friend-remark {
|
||||||
|
border-bottom: 1px dashed #bec3d0;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
color: #736f6f;
|
||||||
|
width: 60%;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon-edit-outline {
|
||||||
|
margin-left: 3px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 好友申请表单 */
|
||||||
|
.friend-from {
|
||||||
|
position: absolute;
|
||||||
|
background: #fbf6f6;
|
||||||
|
height: 80px;
|
||||||
|
z-index: 2;
|
||||||
|
width: 100%;
|
||||||
|
bottom: -80px;
|
||||||
|
left: 0;
|
||||||
|
transition: all 0.5s ease-in-out;
|
||||||
|
|
||||||
|
p {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 7px 5px 5px 15px;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
&:nth-child(2) {
|
||||||
|
float: right;
|
||||||
|
margin-right: 13px;
|
||||||
|
color: #32caff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
height: 31px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 7px 5px 5px 15px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
width: 220px;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.friend-from-show {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|