This commit is contained in:
xiezhijun
2021-08-20 15:58:09 +08:00
18 changed files with 1184 additions and 313 deletions

View File

@ -472,11 +472,15 @@ public class WechatAppletController extends BaseController {
curWxUserInfo.setSex(customerPhysicalSigns.getSex().toString());
curWxUserInfo.setHeight(customerPhysicalSigns.getTall());
curWxUserInfo.setAge(customerPhysicalSigns.getAge());
curWxUserInfo.setStartDate(customerPhysicalSigns.getCreateTime());
curWxUserInfo.setWeight(customerPhysicalSigns.getWeight());
}
} else {
curWxUserInfo.setSex(customerHealthy.getSex().toString());
curWxUserInfo.setHeight(customerHealthy.getTall());
curWxUserInfo.setAge(Math.toIntExact(customerHealthy.getAge()));
curWxUserInfo.setStartDate(customerHealthy.getCreateTime());
curWxUserInfo.setWeight(customerHealthy.getWeight());
}
curWxUserInfo.setCustomerId(AesUtils.encrypt(curWxUserInfo.getCusId().toString()));

View File

@ -1,5 +1,7 @@
package com.stdiet.common.utils.oss;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.stdiet.common.config.AliyunOSSConfig;
@ -7,9 +9,6 @@ import com.stdiet.common.utils.StringUtils;
import com.stdiet.common.utils.file.FileUtils;
import org.springframework.web.multipart.MultipartFile;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
@ -25,6 +24,7 @@ public class AliyunOSSUtils {
//默认文件路径前缀
private static final String default_prefix = "https://stdiet.oss-cn-shenzhen.aliyuncs.com";
private static final String default_prefix2 = "https://v.stdiet.top";
public static OSS getOssClient() {
return new OSSClientBuilder().build(AliyunOSSConfig.EndPoint, AliyunOSSConfig.AccessKeyID, AliyunOSSConfig.AccessKeySecret);
@ -83,6 +83,7 @@ public class AliyunOSSUtils {
/**
* MultipartFile2File
*
* @param multipartFile
* @return
*/
@ -95,11 +96,11 @@ public class AliyunOSSUtils {
//获取最后一个"."的位置
int cutPoint = originalFilename.lastIndexOf(".");
//获取文件名
String prefix = originalFilename.substring(0,cutPoint);
String prefix = originalFilename.substring(0, cutPoint);
//获取后缀名
String suffix = originalFilename.substring(cutPoint + 1);
//创建临时文件,prefix最少三位
file = File.createTempFile((prefix != null && prefix.length() >= 3 ? prefix : prefix+"ab"), suffix);
file = File.createTempFile((prefix != null && prefix.length() >= 3 ? prefix : prefix + "ab"), suffix);
//multipartFile2file
multipartFile.transferTo(file);
//删除临时文件
@ -122,6 +123,7 @@ public class AliyunOSSUtils {
/**
* 上传文件流
*
* @param prefix 路径的前缀路径目录
* @param oranFileName 上传到服务器上的文件路径和名称
* @param file 来自本地的文件或者文件流
@ -152,6 +154,7 @@ public class AliyunOSSUtils {
/**
* 上传文件流
*
* @param prefix 路径的前缀路径目录
* @param oranFileName 上传到服务器上的文件路径和名称
* @param file 来自本地的文件或者文件流
@ -223,19 +226,18 @@ public class AliyunOSSUtils {
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition",
"attachment;fileName=" + FileUtils.setFileDownloadHeader(request, fileName));
FileUtils.writeBytes(streamData , response.getOutputStream());
FileUtils.writeBytes(streamData, response.getOutputStream());
// 关闭OSSClient。
ossClient.shutdown();
}
/**
*
* @param fileUrl
* @return
*/
public static String generatePresignedUrl(String fileUrl){
if(!isAliyunUrl(fileUrl)) {
public static String generatePresignedUrl(String fileUrl) {
if (!isAliyunUrl(fileUrl)) {
return null;
}
// 创建OSSClient实例。
@ -252,11 +254,10 @@ public class AliyunOSSUtils {
}
/**
*
* @param fileUrlList
* @return
*/
public static List<String> generatePresignedUrl(List<String> fileUrlList){
public static List<String> generatePresignedUrl(List<String> fileUrlList) {
List<String> downUrlList = new ArrayList<>();
// 创建OSSClient实例。
@ -265,7 +266,7 @@ public class AliyunOSSUtils {
Date expiration = new Date(System.currentTimeMillis() + expire);
for (String fileUrl : fileUrlList) {
if(isAliyunUrl(fileUrl)){
if (isAliyunUrl(fileUrl)) {
String url = ossClient.generatePresignedUrl(AliyunOSSConfig.Buckets, getObjectName(fileUrl), expiration).toString();
downUrlList.add(url);
}
@ -279,19 +280,19 @@ public class AliyunOSSUtils {
/**
* 判断是否为阿里云OSS路径格式
*
* @param fileUrl
* @return
*/
public static boolean isAliyunUrl(String fileUrl){
return StringUtils.isNotEmpty(fileUrl) && fileUrl.startsWith(default_prefix);
public static boolean isAliyunUrl(String fileUrl) {
return StringUtils.isNotEmpty(fileUrl) && (fileUrl.startsWith(default_prefix) || fileUrl.startsWith(default_prefix2));
}
/**
*
* @param fileUrlList
* @return
*/
public static Map<String, List<String>> generatePresignedUrl(Map<String, List<String>> fileUrlList){
public static Map<String, List<String>> generatePresignedUrl(Map<String, List<String>> fileUrlList) {
Map<String, List<String>> downUrlMap = new HashMap<>();
// 创建OSSClient实例。
@ -303,7 +304,7 @@ public class AliyunOSSUtils {
List<String> urlList = fileUrlList.get(key);
List<String> downList = new ArrayList<>();
for (String fileUrl : urlList) {
if(isAliyunUrl(fileUrl)){
if (isAliyunUrl(fileUrl)) {
downList.add(ossClient.generatePresignedUrl(AliyunOSSConfig.Buckets, getObjectName(fileUrl), expiration).toString());
}
}

View File

@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.stdiet.common.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@ -62,7 +63,7 @@ public class SysCustomerPhysicalSigns {
* 客户体重(斤)
*/
@Excel(name = "客户体重", readConverterExp = "斤=")
private Integer weight;
private BigDecimal weight;
/**
* 客户病史体征id

View File

@ -1,9 +1,11 @@
package com.stdiet.custom.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.stdiet.common.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
@ -28,6 +30,11 @@ public class SysWxUserInfo {
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate;
private BigDecimal weight;
/**
* 昵称
*/

View File

@ -7,6 +7,7 @@ import lombok.Data;
import java.io.Serializable;
@Data
public class VideoResponse implements Serializable {
private static final long serialVersionUID = 1L;
@ -26,47 +27,11 @@ public class VideoResponse implements Serializable {
// 播放等级
private Integer playLevel;
public void setPlayLevel(Integer playLevel) {
this.playLevel = playLevel;
}
public Integer getPlayLevel() {
return playLevel;
}
public String getVideoId() {
return videoId;
}
public void setVideoId(String videoId) {
this.videoId = videoId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCoverUrl() {
if (StringUtils.isNotEmpty(this.coverUrl)) {
return AliyunOSSUtils.generatePresignedUrl(this.coverUrl);
} else {
return AliyunVideoUtils.getVideoCoverUrl(this.videoId);
}
}
public void setCoverUrl(String coverUrl) {
this.coverUrl = coverUrl;
if (StringUtils.isNotEmpty(coverUrl)) {
this.coverUrl = AliyunOSSUtils.generatePresignedUrl(coverUrl);
} else {
this.coverUrl = AliyunVideoUtils.getVideoCoverUrl(this.videoId);
}
public Integer getPlayNum() {
return playNum;
}
public void setPlayNum(Integer playNum) {
this.playNum = playNum;
}
}

View File

@ -208,7 +208,7 @@ public class SysCustomerHeatStatisticsServiceImpl implements ISysCustomerHeatSta
sysCustomerHealthy.setName(sysCustomerPhysicalSigns.getName());
sysCustomerHealthy.setTall(sysCustomerPhysicalSigns.getTall());
sysCustomerHealthy.setAge(sysCustomerPhysicalSigns.getAge().longValue());
sysCustomerHealthy.setWeight(BigDecimal.valueOf(sysCustomerPhysicalSigns.getWeight()));
sysCustomerHealthy.setWeight(sysCustomerPhysicalSigns.getWeight());
}
return sysCustomerHealthy;
}

View File

@ -46,7 +46,7 @@
"clipboard": "^2.0.6",
"core-js": "3.6.5",
"dayjs": "^1.9.1",
"echarts": "4.7.0",
"echarts": "4.9.0",
"element-ui": "2.13.2",
"file-saver": "^2.0.5",
"fuse.js": "3.4.4",

View File

@ -0,0 +1,126 @@
<template>
<div
class="chart_style_wrapper"
ref="echart"
:style="{ height: height, width: width }"
/>
</template>
<script>
import echarts from "echarts";
import _ from "lodash";
require("@/utils/echarts/myShine");
import resize from "@/views/dashboard/mixins/resize";
export default {
mixins: [resize],
name: "CursorChartView",
data() {
return {
chart: undefined,
};
},
props: {
data: {
type: Array,
default: [],
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "30px",
},
},
mounted() {
this.$nextTick(() => {
this.initChart();
});
},
unmounted() {},
methods: {
initChart() {
this.chart = echarts.init(this.$refs.echart, "myShine");
this.chart.on("datazoom", _.debounce(this.handleOnChartDatazoom, 200));
if (this.data.length > 0) {
this.updateChart(this.data);
}
},
updateChart(source) {
const option = {
yAxis: { show: false },
grid: {
top: 0,
left: 10,
right: 10,
bottom: 7,
containLabel: true,
},
xAxis: {
type: "category",
inverse: true,
nameTextStyle: {
color: "#fff",
},
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
textStyle: {
color: "#fff",
},
formatter: (val) => val.substr(5).replace("-", "/"),
},
data: source.map((obj) => obj.name),
},
dataZoom: {
type: "slider",
show: true,
zoomLock: true,
startValue: 0,
endValue: 6,
height: 16,
bottom: 6,
textStyle: {
color: "#fff",
},
handleStyle: {
borderColor: "#fff",
},
},
};
// console.log({ option });
this.chart.clear();
this.chart.setOption(option);
},
handleOnChartDatazoom(params) {
window.postMessage({
type: "PUNCH_LINE_CHART_MESSAGE_DATAZOOM",
end: params.end,
keyVal: "cursor",
start: params.start,
});
},
},
watch: {
data(newVal, oldVal) {
if (newVal) {
this.$nextTick(() => {
this.updateChart(newVal);
});
}
},
},
};
</script>
<style lang="scss" scoped>
.chart_style_wrapper {
background: #4b8aff;
position: absolute;
top: 48px;
}
</style>

View File

@ -6,168 +6,151 @@
@closed="handleOnClosed"
size="45%"
>
<div class="app-container punchLog_drawer_wrapper">
<div class="header">
<section>
<el-button icon="el-icon-view" size="mini" @click="showPunchLogChart()"
>体重趋势图
</el-button>
</section>
<section>
<el-button
icon="el-icon-refresh"
size="mini"
@click="getList"
circle
/>
</section>
</div>
<div class="punchLog_drawer_wrapper" v-loading="loading">
<div v-if="data.length">
<CursorChartView :data="getChartData('weight')" />
<el-table :data="punchLogList" v-loading="planLoading" height="80%">
<el-table-column label="打卡日期" align="center" prop="logTime"/>
<el-table-column label="体重(斤)" align="center" prop="weight"/>
<el-table-column label="饮水量(ml)" align="center" prop="water"/>
<el-table-column label="营养师" align="center" prop="nutritionist" />
<el-table-column label="售后" align="center" prop="afterNutritionist" />
<el-table-column label="操作" align="center" width="160">
<template slot-scope="scope">
<el-button
icon="el-icon-view"
size="mini"
type="text"
@click="showPunchLogDetail(scope.row)"
v-hasPermi="['custom:wxUserLog:query']"
>详情
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['custom:wxUserLog:edit']"
>修改
</el-button>
<el-button
type="text"
icon="el-icon-delete"
v-hasPermi="['custom:wxUserLog:remove']"
@click="handleOnDelete(scope.row)"
>删除</el-button
class="weigth_trend_button"
:style="`left: ${getTextWidth(title) + 30}px`"
@click="showPunchLogChart()"
>体重趋势图</el-button
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
<div
class="chart_zone_style"
v-for="chart in chartList"
:key="chart.keyVal"
>
<LineChartView
v-if="chart.keyVal"
v-bind="chart"
:data="getChartData(chart.keyVal)"
@onClick="handleOnChartClick"
/>
</div>
</div>
<div v-else class="empty_style">暂无打卡记录</div>
</div>
<!-- 详情 -->
<PunchLogDetail ref="punchLogDetailRef"></PunchLogDetail>
<!-- 编辑 -->
<PunchLogEdit ref="punchLogEditRef"></PunchLogEdit>
<!-- 体重趋势图 -->
<PunchLogChart ref="punchLogChartRef"></PunchLogChart>
</el-drawer>
</template>
<script>
import {
addWxUserLog,
delWxUserLog,
exportWxUserLog,
getWxUserLog,
listWxUserLog,
updateWxUserLog,
} from "@/api/custom/wxUserLog";
import { listWxUserLog } from "@/api/custom/wxUserLog";
import { getCustomerPhysicalSignsByCusId } from "@/api/custom/customer";
import LineChartView from "../LineChartView";
import CursorChartView from "../CursorChartView";
import PunchLogDetail from "@/components/PunchLog/PunchLogDetail";
import PunchLogEdit from "@/components/PunchLog/PunchLogEdit";
import PunchLogChart from "@/components/PunchLog/PunchLogChart";
import dayjs from "dayjs";
export default {
name: "CustomerPunchLog",
name: "punchLog",
components: {
PunchLogDetail,PunchLogEdit,PunchLogChart
LineChartView,
CursorChartView,
PunchLogDetail,
PunchLogChart,
},
data() {
return {
open: false,
visible: false,
title: "",
planLoading: false,
data: null,
punchLogList: [],
total: 0,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
customerId: null
},
loading: false,
userObj: null,
sex: 0,
data: [],
// prettier-ignore
chartList: [
{},
{ label: "体重", keyVal: "weight", unit: "斤", extra: undefined },
{ label: "饮水量", keyVal: "water", unit: "毫升", extra: undefined },
{ label: "入睡时间", keyVal: "sleepTime", unit: undefined, extra: undefined },
{ label: "起床时间", keyVal: "wakeupTime", unit: undefined, extra: undefined },
{ label: "熬夜失眠", keyVal: "insomnia", unit: undefined, extra: undefined },
{ label: "运动锻炼", keyVal: "sport", unit: undefined, extra: undefined },
{ label: "情绪状况", keyVal: "emotion", unit: undefined, extra: undefined },
{ label: "排便情况", keyVal: "defecation", unit: undefined, extra: undefined },
{ label: "按营养餐吃", keyVal: "diet", unit: undefined, extra: undefined },
],
};
},
methods: {
showDrawer(data) {
// console.log(data);
this.data = data;
if (this.data == undefined || this.data == null) {
if (!data) {
return;
}
this.punchLogList = [];
this.total = 0;
this.visible = true;
this.title = `${this.data.name}」打卡记录`;
this.getList();
},
getList() {
this.planLoading = true;
this.queryParams.customerId = this.data.id;
listWxUserLog(this.queryParams).then((response) => {
if(response.code == 200){
this.punchLogList = response.rows;
this.total = response.total;
}
this.planLoading = false;
});
},
reset() {
this.visible = true;
this.userObj = data;
this.title = `${this.userObj.name}」打卡情况`;
this.fetchLogDatas();
},
handleOnClosed(){
this.data = null
handleOnClosed() {
this.userObj = undefined;
},
showPunchLogDetail(data){
this.$refs.punchLogDetailRef.showDialog(data);
showPunchLogChart() {
this.$refs.punchLogChartRef.showDialog(this.userObj);
},
showPunchLogChart(){
this.$refs.punchLogChartRef.showDialog(this.data);
getTextWidth(text) {
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
ctx.font = "16px Arial";
const { width } = ctx.measureText(text);
document.body.removeChild(canvas);
return Math.ceil(width);
},
handleUpdate(data){
this.$refs.punchLogEditRef.showDialog(data, () => {
this.getList();
fetchLogDatas() {
this.loading = true;
getCustomerPhysicalSignsByCusId(this.userObj.id).then((res) => {
if (res.data.customerHealthy) {
this.sex = res.data.customerHealthy.sex;
this.chartList[0] = this.sex
? {
label: "生理期",
keyVal: "menstrualPeriod",
unit: undefined,
extra: undefined,
}
: {};
this.chartList[1].extra = `初始体重:${res.data.customerHealthy.weight}`;
}
listWxUserLog({
customerId: this.userObj.id,
}).then((res) => {
if (res.code === 200) {
this.data = res.rows;
}
this.loading = false;
});
});
},
/** 删除按钮操作 */
handleOnDelete(row) {
const ids = row.id;
this.$confirm(
'是否确定删除该用户' + row.logTime + '的打卡记录?',
"警告",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
)
.then(function () {
return delWxUserLog(ids);
})
.then(() => {
this.getList();
this.msgSuccess("删除成功");
})
.catch(function () {});
getChartData(key) {
return this.data.map((obj) => {
let value = obj[key];
value === "Y" && (value = "是");
value === "N" && (value = "否");
return {
id: obj.id,
name: obj.logTime,
value,
};
});
},
handleOnChartClick(id) {
// console.log(id);
const tarData = this.data.find((obj) => obj.id === id);
tarData &&
this.$refs.punchLogDetailRef.showDialog({
sex: this.sex,
...tarData,
});
},
},
};
@ -178,13 +161,22 @@ export default {
}
.punchLog_drawer_wrapper {
overflow: auto;
height: calc(100vh - 77px);
.header {
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: space-between;
.chart_zone_style {
margin: 16px;
border-radius: 8px;
overflow: hidden;
}
.empty_style {
text-align: center;
}
.weigth_trend_button {
position: absolute;
top: 16px;
}
}
</style>

View File

@ -0,0 +1,190 @@
<template>
<el-drawer
:title="title"
:close-on-press-escape="false"
:visible.sync="visible"
@closed="handleOnClosed"
size="45%"
>
<div class="app-container punchLog_drawer_wrapper">
<div class="header">
<section>
<el-button icon="el-icon-view" size="mini" @click="showPunchLogChart()"
>体重趋势图
</el-button>
</section>
<section>
<el-button
icon="el-icon-refresh"
size="mini"
@click="getList"
circle
/>
</section>
</div>
<el-table :data="punchLogList" v-loading="planLoading" height="80%">
<el-table-column label="打卡日期" align="center" prop="logTime"/>
<el-table-column label="体重(斤)" align="center" prop="weight"/>
<el-table-column label="饮水量(ml)" align="center" prop="water"/>
<el-table-column label="营养师" align="center" prop="nutritionist" />
<el-table-column label="售后" align="center" prop="afterNutritionist" />
<el-table-column label="操作" align="center" width="160">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
@click="showPunchLogDetail(scope.row)"
v-hasPermi="['custom:wxUserLog:query']"
>详情
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['custom:wxUserLog:edit']"
>修改
</el-button>
<el-button
type="text"
icon="el-icon-delete"
v-hasPermi="['custom:wxUserLog:remove']"
@click="handleOnDelete(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
<!-- 详情 -->
<PunchLogDetail ref="punchLogDetailRef"></PunchLogDetail>
<!-- 编辑 -->
<PunchLogEdit ref="punchLogEditRef"></PunchLogEdit>
<!-- 体重趋势图 -->
<PunchLogChart ref="punchLogChartRef"></PunchLogChart>
</el-drawer>
</template>
<script>
import {
addWxUserLog,
delWxUserLog,
exportWxUserLog,
getWxUserLog,
listWxUserLog,
updateWxUserLog,
} from "@/api/custom/wxUserLog";
import PunchLogDetail from "@/components/PunchLog/PunchLogDetail";
import PunchLogEdit from "@/components/PunchLog/PunchLogEdit";
import PunchLogChart from "@/components/PunchLog/PunchLogChart";
import dayjs from "dayjs";
export default {
name: "CustomerPunchLog",
components: {
PunchLogDetail,PunchLogEdit,PunchLogChart
},
data() {
return {
open: false,
visible: false,
title: "",
planLoading: false,
data: null,
punchLogList: [],
total: 0,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
customerId: null
},
};
},
methods: {
showDrawer(data) {
// console.log(data);
this.data = data;
if (this.data == undefined || this.data == null) {
return;
}
this.punchLogList = [];
this.total = 0;
this.visible = true;
this.title = `${this.data.name}」打卡记录`;
this.getList();
},
getList() {
this.planLoading = true;
this.queryParams.customerId = this.data.id;
listWxUserLog(this.queryParams).then((response) => {
if(response.code == 200){
this.punchLogList = response.rows;
this.total = response.total;
}
this.planLoading = false;
});
},
reset() {
},
handleOnClosed(){
this.data = null
},
showPunchLogDetail(data){
this.$refs.punchLogDetailRef.showDialog(data);
},
showPunchLogChart(){
this.$refs.punchLogChartRef.showDialog(this.data);
},
handleUpdate(data){
this.$refs.punchLogEditRef.showDialog(data, () => {
this.getList();
});
},
/** 删除按钮操作 */
handleOnDelete(row) {
const ids = row.id;
this.$confirm(
'是否确定删除该用户' + row.logTime + '的打卡记录?',
"警告",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
)
.then(function () {
return delWxUserLog(ids);
})
.then(() => {
this.getList();
this.msgSuccess("删除成功");
})
.catch(function () {});
},
},
};
</script>
<style lang="scss" scoped>
/deep/ :focus {
outline: 0;
}
.punchLog_drawer_wrapper {
height: calc(100vh - 77px);
.header {
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>

View File

@ -0,0 +1,189 @@
import { iconDict } from "./utils";
function getComOption(title, data) {
return {
title: {
text: title,
left: 5,
top: 8,
textStyle: {
// color: "#fff"
}
},
textStyle: {
// fontFamily: "monospace"
},
tooltip: {
show: true,
trigger: "axis",
axisPointer: {
lineStyle: {
type: "dashed"
}
}
},
grid: {
top: 40,
left: 10,
right: 20,
bottom: 10,
containLabel: true
},
dataZoom: {
type: "slider",
show: false,
zoomLock: true,
startValue: 0,
endValue: 6,
height: 16,
bottom: 8,
textStyle: {
color: "#fff"
},
handleStyle: {
// borderColor: "#fff"
}
// filterMode: 'none',
},
graphic: [],
xAxis: {
type: "category",
inverse: true,
nameTextStyle: {
// color: "#fff"
},
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
textStyle: {
// color: "#fff"
},
formatter: val => val.substr(5).replace("-", "/")
},
data: data.map(obj => obj.name)
},
yAxis: {
type: "value",
axisLine: {
show: false
},
axisLabel: {
textStyle: {
// color: "#fff"
}
},
axisTick: {
show: false
},
splitLine: {
show: false
}
},
series: [
{
type: "line",
lineStyle: {
color: "#FF6E67"
},
itemStyle: {
color: "#333"
}
// data,
}
]
};
}
function getOption(type, data, title, unit, extra) {
const option = getComOption(title, data);
option.tooltip.formatter = params => {
const [param] = params;
let value = param.data.oriValue;
// console.log({ type, value });
unit && (value += unit);
return [`日期:${param.data.name}`, `${title}${value}`].join("</br>");
};
if (unit) {
option.graphic.push({
type: "text",
right: 30,
top: 16,
style: {
text: `单位:${unit}`,
// fill: "#fff"
}
});
}
if (extra) {
option.graphic.push({
type: "text",
right: 30,
top: 36,
style: {
text: extra,
// fill: "#fff"
}
});
}
if (type === "water" || type === "weight") {
option.yAxis.max = value => Math.floor(value.max * 1.5);
option.yAxis.min = value => Math.floor(value.min * 0.5);
option.yAxis.splitNumber = 1;
option.series[0].data = data.map(obj => ({
...obj,
label: { show: true },
oriValue: obj.value,
formatter: ({ value }) => (type === "water" ? `${value / 1000}` : value)
}));
} else if (type === "sleepTime" || type === "wakeupTime") {
option.yAxis.max = 24;
option.yAxis.min = 0;
option.yAxis.minInterval = 6;
option.series[0].data = data.map(obj => {
const [hour, minute] = obj.value.split(":");
return {
...obj,
oriValue: obj.value,
value: parseInt(hour) + parseFloat(minute) / 60
};
});
} else if (
type === "emotion" ||
type === "insomnia" ||
type === "sport" ||
type === "diet" ||
type === "defecation" ||
type === "menstrualPeriod"
) {
const tarObj = iconDict[type];
const range = Object.keys(tarObj);
option.grid.left = -20;
// if (type !== 'emotion' && type !== 'defecation') {
option.yAxis.axisLabel.formatter = value => {
return range[value];
};
// } else {
// option.yAxis.axisLabel.show = false;
// }
option.yAxis.max = range.length - 0.5;
option.yAxis.min = -0.5;
option.series[0].data = data.map(obj => ({
...obj,
value: range.indexOf(obj.value),
oriValue: obj.value,
symbol: tarObj[obj.value] ? tarObj[obj.value].imgData : "",
symbolSize: 20
}));
}
return option;
}
export { getOption };

View File

@ -0,0 +1,149 @@
<template>
<div
class="chart_style_wrapper"
ref="echart"
:style="{ height: height, width: width }"
/>
</template>
<script>
import echarts from "echarts";
import _ from "lodash";
require("@/utils/echarts/myShine");
import resize from "@/views/dashboard/mixins/resize";
import { getOption } from "./chartUtils";
export default {
mixins: [resize],
name: "LineChartView",
data() {
return {
chart: undefined,
};
},
props: {
data: {
type: Array,
default: [],
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "200px",
},
label: {
type: String,
default: "",
},
keyVal: {
type: String,
default: "",
},
unit: {
type: String,
default: "",
},
extra: {
type: String,
default: "",
},
},
mounted() {
this.$nextTick(() => {
this.initChart();
});
window.addEventListener("message", this.handleOnMessage);
},
unmounted() {
window.removeEventListener("message", this.handleOnMessage);
},
methods: {
initChart() {
this.chart = echarts.init(this.$refs.echart, "myShine");
this.chart.on("mouseover", this.handleOnChartMouseover);
this.chart.on("mouseout", this.handleOnChartMouseout);
this.chart.on("click", this.handleOnChartClick);
if (this.data.length > 0) {
this.updateChart(this.data);
}
},
updateChart(source) {
const option = getOption(
this.keyVal,
source,
this.label,
this.unit,
this.extra
);
// console.log({ option });
this.chart.clear();
this.chart.setOption(option);
},
handleOnChartClick(params) {
// console.log({ params });
this.$emit("onClick", params.data.id);
},
handleOnChartMouseover(params) {
window.postMessage({
type: "PUNCH_LINE_CHART_MESSAGE_MOUSEOVER",
keyVal: this.keyVal,
seriesIndex: params.seriesIndex,
dataIndex: params.dataIndex,
});
},
handleOnChartMouseout(params) {
window.postMessage({
type: "PUNCH_LINE_CHART_MESSAGE_MOUSEOUT",
keyVal: this.keyVal,
seriesIndex: params.seriesIndex,
dataIndex: params.dataIndex,
});
},
handleOnMessage({ data = {} }) {
if (data.keyVal === this.keyVal) {
return;
}
if (
data.type &&
(data.type === "PUNCH_LINE_CHART_MESSAGE_MOUSEOVER" ||
data.type === "PUNCH_LINE_CHART_MESSAGE_MOUSEOUT")
) {
this.chart &&
this.chart.dispatchAction({
type:
data.type === "PUNCH_LINE_CHART_MESSAGE_MOUSEOVER"
? "showTip"
: "hideTip",
seriesIndex: data.seriesIndex,
dataIndex: data.dataIndex,
});
} else if (
data.type &&
data.type === "PUNCH_LINE_CHART_MESSAGE_DATAZOOM"
) {
this.chart &&
this.chart.dispatchAction({
type: "dataZoom",
end: data.end,
start: data.start,
});
}
},
},
watch: {
data(newVal, oldVal) {
if (newVal) {
this.$nextTick(() => {
this.updateChart(newVal);
});
}
},
},
};
</script>
<style lang="scss" scoped>
.chart_style_wrapper {
background: #FFECEC;
}
</style>

File diff suppressed because one or more lines are too long

View File

@ -22,7 +22,7 @@
>
</div>
<h3>基础信息</h3>
<TableDetailMessage :data="punchLogDetail"></TableDetailMessage>
<TableDetailMessage :data="punchLogDetail" :maxLength="10" />
<h3>食物以及对比照信息</h3>
<div style="height: 370px; overflow: auto">
<div v-if="punchLog != null && punchLog.ingredientDesc">
@ -40,6 +40,7 @@
title="点击大图预览"
:key="'breakfast' + index"
class="food_image_first"
fit="cover"
:src="item"
:preview-src-list="imageUrl"
>
@ -54,6 +55,7 @@
title="点击大图预览"
:key="'lunch' + index"
class="food_image"
fit="cover"
:src="item"
:preview-src-list="imageUrl"
>
@ -68,6 +70,7 @@
title="点击大图预览"
:key="'dinner' + index"
class="food_image"
fit="cover"
:src="item"
:preview-src-list="imageUrl"
>
@ -82,12 +85,19 @@
title="点击大图预览"
:key="'extraMeal' + index"
class="food_image"
fit="cover"
:src="item"
:preview-src-list="imageUrl"
>
</el-image>
</div>
</div>
<div v-if="punchLog != null && punchLog.bodyDesc">
<h4>对比照描述</h4>
<div>
{{ punchLog.bodyDesc }}
</div>
</div>
<div v-if="punchLog.imagesUrl.bodyImages.length > 0">
<h4>体型对比照</h4>
<div>
@ -96,6 +106,7 @@
title="点击大图预览"
:key="index"
style="width: 300px; height: 300px"
fit="cover"
:src="item"
:preview-src-list="imageUrl"
>
@ -167,19 +178,21 @@ export default {
punchLogDetail: [],
//打卡详情的标题,按竖显示
punchTitleData: [
["姓名", "体重(斤)", "饮水量(ml)"],
["睡觉时间", "起床时间", "运动锻炼"],
["情绪", "按食谱进食", "其他食物"],
["熬夜失眠", "起床排便", "是否便秘"],
["服务建议", "评分", "点评内容"],
[],
["睡觉时间", "情绪状况", "运动锻炼"],
["起床时间", "情绪描述", "运动描述"],
["排便情况", "按营养餐吃", "食谱外食物"],
["排便描述", "营养餐感受", "熬夜失眠"],
["评分", "点评内容"],
],
//打卡详情的属性名称,与标题对应,按竖显示
punchValueData: [
["customerName", "weight", "water"],
["sleepTime", "wakeupTime", "sport"],
["emotion", "diet", "slyEatFood"],
["insomnia", "defecation", "constipation"],
["remark", "executionScore", "comment"],
[],
["sleepTime", "emotion", "sport"],
["wakeupTime", "emotionDesc", "sportDesc"],
["defecation", "diet", "slyEatFood"],
["defecationDesc", "dietDesc", "insomnia"],
["executionScore", "comment"],
],
commentVisible: false,
@ -212,6 +225,13 @@ export default {
},
showDialog(data, callback) {
this.data = data;
if (data.sex) {
this.punchTitleData[0] = ["体重(斤)", "饮水量(ml)", "生理期"];
this.punchValueData[0] = ["weight", "water", "menstrualPeriod"];
} else {
this.punchTitleData[0] = ["体重(斤)", "饮水量(ml)"];
this.punchValueData[0] = ["weight", "water"];
}
this.callback = callback;
this.commentFlag = false;
this.title = `${data.customerName}` + " " + `${data.logTime}」打卡记录`;
@ -228,6 +248,9 @@ export default {
res.data.defecation = res.data.defecation === "Y" ? "是" : "否";
res.data.constipation = res.data.constipation === "Y" ? "是" : "否";
res.data.isScore = res.data.executionScore == null ? "否" : "是";
res.data.menstrualPeriod =
res.data.menstrualPeriod == "N" ? "否" : "是";
this.punchLogDetail = [];
for (let i = 0; i < this.punchTitleData.length; i++) {
this.punchLogDetail.push({
@ -300,13 +323,17 @@ export default {
<style lang="scss" scoped>
.food_image_first {
width: 280px;
height: 300px;
width: 160px;
height: 160px;
border-radius: 16px;
margin: 8px;
}
.food_image {
width: 280px;
height: 300px;
width: 160px;
height: 160px;
//margin-left:10px
margin: 8px;
border-radius: 16px;
}
</style>

View File

@ -1,58 +1,79 @@
<template>
<el-table :show-header="false" :data="data" border :cell-style="columnStyle" style="width: 100%;">
<el-table-column width="140" prop="attr_name_one">
</el-table-column>
<el-table
:show-header="false"
:data="data"
border
:cell-style="columnStyle"
style="width: 100%"
>
<el-table-column width="100" prop="attr_name_one"> </el-table-column>
<el-table-column prop="value_one">
<template slot-scope="scope">
<AutoHideMessage :data="scope.row.value_one == null ? '' : (scope.row.value_one+'')" :maxLength="20"/>
<AutoHideMessage
:data="scope.row.value_one == null ? '' : scope.row.value_one + ''"
:maxLength="10"
/>
</template>
</el-table-column>
<el-table-column width="140" prop="attr_name_two"></el-table-column>
<el-table-column width="100" prop="attr_name_two"></el-table-column>
<el-table-column prop="value_two">
<template slot-scope="scope">
<AutoHideMessage :data="scope.row.value_two == null ? '' : (scope.row.value_two+'')" :maxLength="20"/>
<AutoHideMessage
:data="scope.row.value_two == null ? '' : scope.row.value_two + ''"
:maxLength="10"
/>
</template>
</el-table-column>
<el-table-column width="140" prop="attr_name_three"></el-table-column>
<el-table-column width="100" prop="attr_name_three"></el-table-column>
<el-table-column prop="value_three">
<template slot-scope="scope">
<AutoHideMessage :data="scope.row.value_three == null ? '' : (scope.row.value_three+'')" :maxLength="20"/>
<AutoHideMessage
:data="
scope.row.value_three == null ? '' : scope.row.value_three + ''
"
:maxLength="10"
/>
</template>
</el-table-column>
</el-table>
</template>
<script>
import AutoHideMessage from "@/components/AutoHideMessage";
export default {
import AutoHideMessage from "@/components/AutoHideMessage";
export default {
name: "TableDetailMessage",
data() {
return {
};
return {};
},
props: {
data: {}
data: {},
maxLength: {
type: Number,
default: 20,
},
computed: {
},
computed: {},
components: {
AutoHideMessage
AutoHideMessage,
},
methods: {
// 自定义列背景色
columnStyle({ row, column, rowIndex, columnIndex }) {
if (columnIndex == 0 || columnIndex == 2 || columnIndex == 4 || columnIndex == 6) {
if (
columnIndex == 0 ||
columnIndex == 2 ||
columnIndex == 4 ||
columnIndex == 6
) {
//第三第四列的背景色就改变了2和3都是列数的下标
return "background:#f3f6fc;font-weight:bold";
}else{
} else {
return "background:#ffffff;";
}
}
}
};
},
},
};
</script>
<style>
</style>

View File

@ -21,7 +21,7 @@ function connect() {
intervalRef && clearInterval(intervalRef);
setInterval(() => {
ws.send("ping");
ws && ws.send("ping");
}, 30000);
window.addEventListener("message", handleOnMessageReceive);
@ -39,7 +39,7 @@ function connect() {
ws.onerror = event => {
// console.log({ event });
ws.close();
ws && ws.close();
ws = undefined;
window.removeEventListener("message", handleOnMessageReceive);

View File

@ -653,6 +653,12 @@ export default {
this.physicalSignsList = response.rows;
});
},
activated() {
if (this.$route.query.cusName) {
this.queryParams.name = this.$route.query.cusName;
this.handleQuery();
}
},
computed: {
isPartner() {
return this.roles && this.roles.includes("partner");

View File

@ -32,7 +32,12 @@
/>
</el-form-item>
<el-form-item label="营养师" prop="nutritionistId">
<el-select v-model="queryParams.nutritionistId" clearable filterable placeholder="请选择">
<el-select
v-model="queryParams.nutritionistId"
clearable
filterable
placeholder="请选择"
>
<el-option
v-for="dict in nutritionistIdOptions.slice(1)"
:key="dict.dictValue"
@ -42,7 +47,12 @@
</el-select>
</el-form-item>
<el-form-item label="售后" prop="afterNutritionistId">
<el-select v-model="queryParams.afterNutritionistId" clearable filterable placeholder="请选择">
<el-select
v-model="queryParams.afterNutritionistId"
clearable
filterable
placeholder="请选择"
>
<el-option
v-for="dict in afterSaleIdOptions.slice(1)"
:key="dict.dictValue"
@ -52,7 +62,11 @@
</el-select>
</el-form-item>
<el-form-item label="打卡日期" prop="logTimeScope" style="margin-left:15px">
<el-form-item
label="打卡日期"
prop="logTimeScope"
style="margin-left: 15px"
>
<el-date-picker
v-model="logTimeScope"
type="daterange"
@ -153,7 +167,16 @@
<span>{{ parseTime(scope.row.logTime, "{y}-{m}-{d}") }}</span>
</template>
</el-table-column>
<el-table-column label="姓名" align="center" prop="customerName" />
<el-table-column label="姓名" align="center" prop="customerName">
<template slot-scope="scope">
<div
@click="handleOnNameClick(scope.row.customerName)"
class="user_name_style"
>
{{ scope.row.customerName }}
</div>
</template>
</el-table-column>
<el-table-column label="当天体重" align="center" prop="weight">
<template slot-scope="scope">
<span>{{ `${scope.row.weight}` }}</span>
@ -171,7 +194,6 @@
<el-table-column label="营养师" align="center" prop="nutritionist" />
<el-table-column label="售后" align="center" prop="afterNutritionist" />
<el-table-column
label="睡觉时间"
align="center"
@ -192,14 +214,12 @@
prop="sport"
:formatter="sportFormat"
/>
<el-table-column
label="情绪"
align="center"
prop="emotion"
width="120"
>
<el-table-column label="情绪" align="center" prop="emotion" width="120">
<template slot-scope="scope">
<AutoHideMessage :maxLength="4" :data="scope.row.emotion"></AutoHideMessage>
<AutoHideMessage
:maxLength="4"
:data="scope.row.emotion"
></AutoHideMessage>
</template>
</el-table-column>
@ -216,7 +236,10 @@
width="120"
>
<template slot-scope="scope">
<AutoHideMessage :maxLength="4" :data="scope.row.slyEatFood"></AutoHideMessage>
<AutoHideMessage
:maxLength="4"
:data="scope.row.slyEatFood"
></AutoHideMessage>
</template>
</el-table-column>
<el-table-column
@ -315,7 +338,7 @@ import { mapGetters } from "vuex";
import PunchLogDetail from "@/components/PunchLog/PunchLogDetail";
import PunchLogEdit from "@/components/PunchLog/PunchLogEdit";
import AutoHideMessage from "@/components/AutoHideMessage";
import NotPunchCustomer from "@/components/PunchLog/NotPunchCustomer"
import NotPunchCustomer from "@/components/PunchLog/NotPunchCustomer";
import dayjs from "dayjs";
export default {
name: "WxUserLog",
@ -356,7 +379,7 @@ export default {
appid: null,
phone: null,
nutritionistId: null,
afterNutritionistId: null
afterNutritionistId: null,
},
// 表单参数
form: {},
@ -364,14 +387,17 @@ export default {
rules: {},
logTimePickerOptions: {
disabledDate(time) {
return time.getTime() > dayjs()
return time.getTime() > dayjs();
},
},
logTimeScope: null
logTimeScope: null,
};
},
components:{
PunchLogDetail,AutoHideMessage,PunchLogEdit,NotPunchCustomer
components: {
PunchLogDetail,
AutoHideMessage,
PunchLogEdit,
NotPunchCustomer,
},
created() {
this.getList();
@ -396,15 +422,21 @@ export default {
// 售后字典
"afterSaleIdOptions",
// 主营养师字典
"nutritionistIdOptions"
"nutritionistIdOptions",
]),
},
methods: {
/** 查询微信用户记录列表 */
getList() {
this.loading = true;
this.queryParams.beginTime = this.logTimeScope && this.logTimeScope.length > 0 ? this.logTimeScope[0] : null;
this.queryParams.endTime = this.logTimeScope && this.logTimeScope.length > 0 ? this.logTimeScope[1] : null;
this.queryParams.beginTime =
this.logTimeScope && this.logTimeScope.length > 0
? this.logTimeScope[0]
: null;
this.queryParams.endTime =
this.logTimeScope && this.logTimeScope.length > 0
? this.logTimeScope[1]
: null;
listWxUserLog(this.queryParams).then((response) => {
this.wxUserLogList = response.rows;
this.total = response.total;
@ -526,15 +558,11 @@ export default {
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$confirm(
'是否确认删除该用户的打卡记录?',
"警告",
{
this.$confirm("是否确认删除该用户的打卡记录?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
)
})
.then(function () {
return delWxUserLog(ids);
})
@ -544,8 +572,8 @@ export default {
})
.catch(function () {});
},
showPunchLogDetail(data){
this.$refs.punchLogDetailRef.showDialog(data,() => {
showPunchLogDetail(data) {
this.$refs.punchLogDetailRef.showDialog(data, () => {
this.getList();
});
},
@ -565,10 +593,28 @@ export default {
})
.catch(function () {});
},
showNotLunch(){
this.queryParams.startDate = this.logTimeScope && this.logTimeScope.length > 0 ? this.logTimeScope[0] : null;
this.$refs.notPunchCustomerRef.showDialog(this.queryParams, this.nutritionistIdOptions,this.afterSaleIdOptions);
}
handleOnNameClick(name) {
// console.log({ name });
this.$router.push(`/customer?cusName=${name}`);
},
showNotLunch() {
this.queryParams.startDate =
this.logTimeScope && this.logTimeScope.length > 0
? this.logTimeScope[0]
: null;
this.$refs.notPunchCustomerRef.showDialog(
this.queryParams,
this.nutritionistIdOptions,
this.afterSaleIdOptions
);
},
},
};
</script>
<style lang="scss" scoped>
.app-container {
.user_name_style {
cursor: pointer;
}
}
</style>