diff --git a/components/html2canvas/html2canvas.vue b/components/html2canvas/html2canvas.vue
new file mode 100644
index 0000000..37bb834
--- /dev/null
+++ b/components/html2canvas/html2canvas.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/r-canvas/r-canvas.js b/components/r-canvas/r-canvas.js
new file mode 100644
index 0000000..b2c7dbe
--- /dev/null
+++ b/components/r-canvas/r-canvas.js
@@ -0,0 +1,735 @@
+export default{
+ data(){
+ return{
+ system_info:{}, //system info
+ canvas_width:0, //canvas width px
+ canvas_height:0, //canvas height px
+ ctx:null, //canvas object
+ canvas_id:null, //canvas id
+ hidden:false,//Whether to hide canvas
+ scale:1,//canvas scale
+ r_canvas_scale:1,
+ if_ctx:true
+ }
+ },
+ methods:{
+ /**
+ * save r-canvas.vue object
+ * @param {Object} that
+ */
+ // saveThis(that){
+ // rCanvasThis = that
+ // },
+ /**
+ * Draw round rect text
+ * @param {Object} config
+ * @param {Number} config.x x坐标
+ * @param {Number} config.y y坐标
+ * @param {Number} config.w 宽度
+ * @param {Number} config.h 高度
+ * @param {Number} config.radius 圆角弧度
+ * @param {String} config.fill_color 矩形颜色
+ */
+ fillRoundRect(config) {
+ return new Promise((resolve,reject)=>{
+ let x = this.compatibilitySize(parseFloat(config.x)*this.scale)
+ let y = this.compatibilitySize(parseFloat(config.y)*this.scale)
+ let w = this.compatibilitySize(parseFloat(config.w)*this.scale)
+ let h = this.compatibilitySize(parseFloat(config.h)*this.scale)
+ let radius = config.radius?parseFloat(config.radius)*this.scale:10*this.scale
+
+ let fill_color = config.fill_color || "black"
+ // The diameter of the circle must be less than the width and height of the rectangle
+ if (2 * radius > w || 2 * radius > h) {
+ reject("The diameter of the circle must be less than the width and height of the rectangle")
+ return false;
+ }
+ this.ctx.save();
+ this.ctx.translate(x, y);
+ //
+ this.drawRoundRectPath({
+ w: w,
+ h: h,
+ radius: radius
+ });
+ this.ctx.fillStyle = fill_color
+ this.ctx.fill();
+ this.ctx.restore();
+ resolve()
+ })
+ },
+ /**
+ * Draws the sides of a rounded rectangle
+ * @param {Object} config
+ * @param {Number} config.w 宽度
+ * @param {Number} config.h 高度
+ * @param {Number} config.radius 圆角弧度
+ */
+ drawRoundRectPath(config) {
+ this.ctx.beginPath(0);
+ this.ctx.arc(config.w - config.radius, config.h - config.radius, config.radius, 0, Math.PI / 2);
+ this.ctx.lineTo(config.radius, config.h);
+ this.ctx.arc(config.radius, config.h - config.radius, config.radius, Math.PI / 2, Math.PI);
+ this.ctx.lineTo(0, config.radius);
+ this.ctx.arc(config.radius, config.radius, config.radius, Math.PI, Math.PI * 3 / 2);
+ this.ctx.lineTo(config.w - config.radius, 0);
+ this.ctx.arc(config.w - config.radius, config.radius, config.radius, Math.PI * 3 / 2, Math.PI * 2);
+ this.ctx.lineTo(config.w, config.h - config.radius);
+ this.ctx.closePath();
+ },
+ /**
+ * Draw special Text,line wrapping is not supported
+ * @param {Object} config
+ * @param {String} config.text 文字
+ * @param {Number} config.x x坐标
+ * @param {Number} config.y y坐标
+ * @param {String} config.font_color 文字颜色
+ * @param {String} config.font_family 文字字体
+ * @param {Number} config.font_size 文字大小(px)
+ */
+ drawSpecialText(params){
+ let general = params.general
+ let list = params.list
+ return new Promise(async (resolve,reject)=>{
+ if(!general){
+ reject("general cannot be empty:101")
+ return;
+ }else if(list && list.length>0){
+ for(let i in list){
+ if(i != 0){
+ let font_size = list[i-1].font_size?parseFloat(list[i-1].font_size):20
+ this.ctx.setFontSize(font_size)
+ general.x = parseFloat(general.x) + this.ctx.measureText(list[i-1].text).width
+ }
+ list[i].x = general.x
+ list[i].y = general.y + (list[i].margin_top?parseFloat(list[i].margin_top):0)
+ await this.drawText(list[i])
+ }
+ resolve()
+ }else{
+ reject("The length of config arr is less than 0")
+ return;
+ }
+
+ })
+ },
+ /**
+ * array delete empty
+ * @param {Object} arr
+ */
+ arrDeleteEmpty(arr){
+ let newArr = []
+ for(let i in arr){
+ if(arr[i]){
+ newArr.push(arr[i])
+ }
+ }
+ return newArr
+ },
+ /**
+ * Draw Text,support line
+ * @param {Object} config
+ * @param {String} config.text 文字
+ * @param {Number} config.max_width 文字最大宽度(大于宽度自动换行)
+ * @param {Number} config.line_height 文字上下行间距
+ * @param {Number} config.x x坐标
+ * @param {Number} config.y y坐标
+ * @param {String} config.font_color 文字颜色
+ * @param {String} config.font_family 文字字体 默认值:Arial
+ * @param {String} config.text_align 文字对齐方式(left/center/right)
+ * @param {Number} config.font_size 文字大小(px)
+ * @param {Boolean} config.line_through_height 中划线大小
+ * @param {Boolean} config.line_through_color 中划线颜色
+ * @param {String} config.font_style 规定文字样式
+ * @param {String} config.font_variant 规定字体变体
+ * @param {String} config.font_weight 规定字体粗细
+ * @param {String} config.line_through_cap 线末端类型
+ * @param {String} config.line_clamp 最大行数
+ * @param {String} config.line_clamp_hint 超过line_clamp后,尾部显示的自定义标识 如 ...
+ * @param {String} config.is_line_break 是否开启换行符换行
+ *
+ */
+ drawText(config,configuration = {}){
+
+ configuration['line_num'] = configuration.line_num?configuration.line_num:0
+ configuration['text_width'] = configuration.text_width?configuration.text_width:0
+
+ return new Promise(async (resolve,reject)=>{
+
+ if(config.text){
+
+ let draw_width = 0,draw_height = 0,draw_x = config.x,draw_y = config.y
+ let font_size = config.font_size?(parseFloat(config.font_size)*this.scale):(20*this.scale)
+ let font_color = config.font_color || "#000"
+ let font_family = config.font_family || "Arial"
+ let line_height = config.line_height || config.font_size || 20
+ let text_align = config.text_align || "left"
+ let font_weight = config.font_weight || "normal"
+ let font_variant = config.font_variant || "normal"
+ let font_style = config.font_style || "normal"
+ let line_clamp_hint = config.line_clamp_hint || '...'
+ let lineBreakJoinText = ""
+ let max_width = config.max_width?parseFloat(config.max_width)*this.scale:0
+ // checkout is line break
+ if(config.is_line_break){
+ let splitTextArr = config.text.split(/[\n]/g)
+ if(splitTextArr && splitTextArr.length > 0){
+ let newSplitTextArr = this.arrDeleteEmpty(splitTextArr)
+ if(newSplitTextArr && newSplitTextArr.length > 0){
+ lineBreakJoinText = newSplitTextArr.slice(1).join("\n")
+ config.text = newSplitTextArr[0]
+ }else{
+ reject("Text cannot be empty:103")
+ return
+ }
+ }else{
+ reject("Text cannot be empty:102")
+ return
+ }
+ }
+
+ this.ctx.setFillStyle(font_color) // color
+ this.ctx.textAlign = text_align;
+ this.ctx.font = `${font_style} ${font_variant} ${font_weight} ${parseInt(font_size)}px ${font_family}`
+ if(configuration.text_width >= this.ctx.measureText(config.text).width){
+ draw_width = configuration.text_width
+ }else if(max_width > 0){
+ draw_width = max_width < this.ctx.measureText(config.text).width ? this.resetCompatibilitySize(max_width) : this.resetCompatibilitySize(this.ctx.measureText(config.text).width)
+ }else{
+ draw_width = this.ctx.measureText(config.text).width
+ }
+ configuration.text_width = draw_width / this.scale
+ if( max_width && this.compatibilitySize(this.ctx.measureText(config.text).width) > this.compatibilitySize(max_width)){
+ let current_text = ""
+ let text_arr = config.text.split("")
+ for(let i in text_arr){
+ if( this.compatibilitySize(this.ctx.measureText(current_text+text_arr[i]).width) > this.compatibilitySize(max_width) ){
+ // Hyphenation that is greater than the drawable width continues to draw
+ if(config.line_clamp && parseInt(config.line_clamp) == 1){
+ // Subtracting the current_text tail width from the line_clamp_hint width
+ let current_text_arr = current_text.split('')
+ let json_current_text = ''
+ while(true){
+ current_text_arr = current_text_arr.slice(1)
+ json_current_text = current_text_arr.join('')
+ if(this.compatibilitySize(this.ctx.measureText(json_current_text).width) <= this.compatibilitySize(this.ctx.measureText(line_clamp_hint).width)){
+ current_text = current_text.replace(json_current_text,'')
+ break;
+ }
+ }
+ configuration.line_num += 1
+ this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
+ this.ctx.fillText(current_text + line_clamp_hint, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
+ }else{
+ configuration.line_num += 1
+ this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
+ this.ctx.fillText(current_text, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
+ config.text = text_arr.slice(i).join("")
+ config.y = config.y + line_height
+ if(config.line_clamp){
+ config.line_clamp = parseInt(config.line_clamp) - 1
+ }
+ await this.drawText(config,configuration)
+ }
+
+ break;
+ }else{
+ current_text = current_text+text_arr[i]
+ }
+ }
+ }else{
+ if(config.line_through_height){
+ let x = parseFloat(config.x)*this.scale
+ let w
+ let y = parseFloat(config.y)*this.scale - (font_size / 2.6)
+ if(text_align == "left"){
+ w = this.ctx.measureText(config.text).width/1.1 + parseFloat(config.x)*this.scale
+ }else if(text_align == "right"){
+ w = parseFloat(config.x)*this.scale - this.ctx.measureText(config.text).width/1.1
+ }else if(text_align == "center"){
+ x = parseFloat(config.x)*this.scale - this.ctx.measureText(config.text).width / 1.1 / 2
+ w = parseFloat(config.x)*this.scale + this.ctx.measureText(config.text).width / 1.1 / 2
+ }
+ this.drawLineTo({
+ x:x,
+ y:y,
+ w:w,
+ h:y,
+ line_width:config.line_through_height,
+ line_color:config.line_through_color,
+ line_cap:config.line_through_cap
+ })
+ }
+ configuration.line_num += 1
+ this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
+ this.ctx.fillText(config.text, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
+ if(config.line_clamp){
+ config.line_clamp = parseInt(config.line_clamp) - 1
+ }
+ }
+ if(lineBreakJoinText){
+ await this.drawText({...config,text:lineBreakJoinText,y:config.y + line_height},configuration)
+ }
+ draw_height = config.font_size * configuration.line_num
+ draw_width = configuration.text_width
+ resolve({draw_width,draw_height,draw_x,draw_y})
+ }else{
+ reject("Text cannot be empty:101")
+ }
+ })
+ },
+ /**
+ * Draw Line
+ * @param {Object} config
+ * @param {Object} config.x x坐标
+ * @param {Object} config.y y坐标
+ * @param {Object} config.w 线的宽度
+ * @param {Object} config.h 线的高度
+ * @param {Object} config.line_width 线的宽度
+ * @param {Object} config.line_color 线条颜色
+ */
+ drawLineTo(config){
+ let x = this.compatibilitySize(config.x)
+ let y = this.compatibilitySize(config.y)
+ let w = this.compatibilitySize(config.w)
+ let h = this.compatibilitySize(config.h)
+ let line_width = config.line_width?parseFloat(config.line_width)*this.scale:1*this.scale
+ let line_color = config.line_color || "black"
+ let line_cap = config.line_cap || "butt"
+ this.ctx.beginPath()
+ this.ctx.lineCap = line_cap
+ this.ctx.lineWidth = line_width
+ this.ctx.strokeStyle = line_color
+ this.ctx.moveTo(x,y)
+ this.ctx.lineTo(w,h)
+ this.ctx.stroke()
+ },
+ /**
+ * Compatibility px
+ * @param {Object} size
+ */
+ compatibilitySize(size) {
+ let canvasSize = (parseFloat(size) / 750) * this.system_info.windowWidth
+ canvasSize = parseFloat(canvasSize * 2)
+ return canvasSize
+ },
+ /**
+ * Restore compatibility px
+ * @param {Object} size
+ */
+ resetCompatibilitySize(size) {
+ let canvasSize = (parseFloat(size/2)/this.system_info.windowWidth) * 750
+ return canvasSize
+ },
+ /**
+ * Init canvas
+ */
+ init(config){
+ return new Promise(async (resolve,reject)=>{
+ if(!config.canvas_id){
+ reject("Canvas ID cannot be empty, please refer to the usage example")
+ return;
+ }
+ this.hidden = config.hidden
+ this.canvas_id = config.canvas_id
+ let system_info = await uni.getSystemInfoSync()
+ this.system_info = system_info
+ this.scale = config.scale&&parseFloat(config.scale)>0?parseInt(config.scale):1
+ this.canvas_width = (config.canvas_width ? this.compatibilitySize(config.canvas_width) : system_info.windowWidth) * this.scale
+ this.canvas_height = (config.canvas_height ? this.compatibilitySize(config.canvas_height) : system_info.windowHeight) * this.scale,
+ this.r_canvas_scale = 1/this.scale
+ this.ctx = uni.createCanvasContext(this.canvas_id,this)
+ this.setCanvasConfig({
+ global_alpha:config.global_alpha?parseFloat(config.global_alpha):1,
+ backgroundColor:config.background_color?config.background_color:"#fff"
+ })
+ resolve()
+ })
+ },
+ /**
+ * clear canvas all path
+ */
+ clearCanvas(){
+ return new Promise(async (resolve,reject)=>{
+ if(!this.ctx){
+ reject("canvas is not initialized:101")
+ return
+ }else{
+ this.ctx.clearRect(0,0,parseFloat(this.canvas_width)*this.scale,parseFloat(this.canvas_height)*this.scale)
+ await this.draw()
+ resolve()
+ }
+ })
+ },
+ /**
+ * Set canvas config
+ * @param {Object} config
+ */
+ setCanvasConfig(config){
+ this.ctx.globalAlpha = config.global_alpha
+ this.ctx.fillStyle = config.backgroundColor
+ this.ctx.fillRect(0, 0, parseFloat(this.canvas_width)*this.scale, parseFloat(this.canvas_height)*this.scale)
+ },
+ /**
+ * set canvas width
+ * @param {Object} width
+ */
+ setCanvasWidth(width){
+ if(!width){
+ uni.showToast({
+ title:'setCanvasWidth:width error',
+ icon:'none'
+ })
+ }
+ this.canvas_width = this.compatibilitySize(parseFloat(width)) * this.scale
+ this.ctx.width = this.canvas_width
+ },
+ /**
+ * set canvas height
+ * @param {Object} height
+ */
+ setCanvasHeight(height){
+ if(!height){
+ uni.showToast({
+ title:'setCanvasWidth:height error',
+ icon:'none'
+ })
+ }
+ this.canvas_height = this.compatibilitySize(parseFloat(height)) * this.scale
+ this.ctx.height = this.canvas_height
+ },
+ /**
+ * Draw to filepath
+ */
+ draw(callback){
+ return new Promise((resolve,reject)=>{
+ let stop = setTimeout(()=>{
+ this.ctx.draw(false,setTimeout(()=>{
+ uni.canvasToTempFilePath({
+ canvasId: this.canvas_id,
+ quality: 1,
+ success: (res)=>{
+ console.log('res',res)
+ resolve(res)
+ callback && callback(res)
+ },
+ fail:(err)=>{
+ reject(JSON.stringify(err)|| "Failed to generate poster:101")
+ }
+ },this)
+ },300))
+ clearTimeout(stop)
+ },300)
+ })
+ },
+ /**
+ * draw rect
+ * @param {Number} config.x x坐标
+ * @param {Number} config.y y坐标
+ * @param {Number} config.w 图形宽度(px)
+ * @param {Number} config.h 图形高度(px)
+ * @param {Number} config.color 图形颜色
+ * @param {Number} config.is_radius 是否开启圆图(1.1.6及以下版本废弃,请使用border_radius)
+ * @param {Number} config.border_width 边框大小
+ * @param {Number} config.border_color 边框颜色
+ *
+ */
+ drawRect(config){
+ return new Promise(async (resolve,reject)=>{
+ if(!config.border_width || config.border_width <=0){
+ config.border_width = 0
+ }else{
+ config.border_width = parseFloat(config.border_width)
+ }
+ if(parseFloat(config.border_width) > 0){
+ let sub_config = JSON.parse(JSON.stringify(config))
+ sub_config.border_width = 0
+ sub_config.w = config.w + config.border_width
+ sub_config.h = config.h + config.border_width
+ sub_config.color = config.border_color || 'black'
+ if(sub_config.border_radius){
+ sub_config.border_radius = parseFloat(sub_config.border_radius) + parseFloat(config.border_width) / 2
+ }
+ await this.drawRect(sub_config)
+ }
+
+ let color = config.color || 'white'
+ config.x = (parseFloat(config.x) + config.border_width / 2)
+ config.y = (parseFloat(config.y) + config.border_width / 2)
+ config['color'] = color
+ this.ctx.fillStyle = color;
+ if(config.is_radius || config.border_radius){
+ this.setNativeBorderRadius(config)
+ this.ctx.fill()
+ }else{
+ console.log('config.border_width',config.border_width)
+ this.ctx.fillRect(this.compatibilitySize(config.x*this.scale),this.compatibilitySize(config.y*this.scale),this.compatibilitySize(parseFloat(config.w)*this.scale),this.compatibilitySize(parseFloat(config.h)*this.scale))
+ }
+ resolve()
+ })
+ },
+ /**
+ * Draw image
+ * @param {Object} config
+ * @param {String} config.url 图片链接
+ * @param {Number} config.x x坐标
+ * @param {Number} config.y y坐标
+ * @param {Number} config.w 图片宽度(px)
+ * @param {Number} config.h 图片高度(px)
+ * @param {Number} config.border_width 边大小
+ * @param {Number} config.border_color 边颜色
+ * @param {Number} config.is_radius 是否开启圆图(1.1.6及以下版本废弃,请使用border_radius)
+ * @param {Number} config.border_radius 圆角弧度
+ */
+ drawImage(config){
+ return new Promise(async (resolve,reject)=>{
+ if(config.url){
+ let type = 0 // 1、network image 2、native image 3、base64 image
+ let image_url
+ let reg = /^https?/ig;
+ if(reg.test(config.url)){
+ type = 1
+ }else{
+ if((config.url.indexOf("data:image/png;base64") != -1) || config.url.indexOf("data:image/jpeg;base64") != -1 || config.url.indexOf("data:image/gif;base64") != -1){
+ type = 3
+ }else{
+ type = 2
+ }
+ }
+ if(type == 1){
+ // network image
+ await this.downLoadNetworkFile(config.url).then(res=>{ // two function
+ image_url = res
+ }).catch(err=>{
+ reject(err)
+ return;
+ })
+ }else if(type == 2){
+ // native image
+ const imageInfoResult = await uni.getImageInfo({
+ src: config.url
+ });
+ try{
+ if(imageInfoResult.length <= 1){
+ reject(imageInfoResult[0].errMsg + ':404')
+ return
+ }
+ }catch(e){
+ reject(e+':500')
+ return
+ }
+ let base64 = await this.urlToBase64({url:imageInfoResult[1].path})
+ // #ifdef MP-WEIXIN
+ await this.base64ToNative({url:base64}).then(res=>{
+ image_url = res
+ }).catch(err=>{
+ reject(JSON.stringify(err)+":501")
+ return;
+ })
+ // #endif
+ // #ifndef MP-WEIXIN
+ image_url = base64
+ // #endif
+
+ }else if(type == 3){
+ // #ifdef MP-WEIXIN
+ await this.base64ToNative({url:config.url}).then(res=>{
+ image_url = res
+ }).catch(err=>{
+ reject(JSON.stringify(err)+":500")
+ return;
+ })
+ // #endif
+ // #ifndef MP-WEIXIN
+ image_url = config.url
+ // #endif
+ }else{
+ reject("Other Type Errors:101")
+ return
+ }
+ if(config.border_width){
+ let border_radius = 0
+ if(config.border_radius){
+ let multiple = config.w / config.border_radius
+ border_radius = (parseFloat(config.w) + parseFloat(config.border_width)) / multiple
+ }
+ // drawRect
+ await this.drawRect({
+ x:parseFloat(config.x) - parseFloat(config.border_width)/2,
+ y:parseFloat(config.y) - parseFloat(config.border_width)/2,
+ w:parseFloat(config.w) + parseFloat(config.border_width),
+ h:parseFloat(config.h) + parseFloat(config.border_width),
+ color:config.border_color,
+ border_radius:border_radius,
+ border_width:config.border_width,
+ is_radius:config.is_radius
+ })
+ }
+
+
+
+ if(config.border_radius){
+ config.color = config.color?config.color:'rgba(0,0,0,0)'
+
+ // 圆角有白边,+0.5的误差
+ config.w = config.w + 0.3
+ config.h = config.h + 0.3
+
+ this.setNativeBorderRadius(config)
+ }else if(config.is_radius){
+ //已废弃 is_radius
+ this.ctx.setStrokeStyle("rgba(0,0,0,0)")
+ this.ctx.save()
+ this.ctx.beginPath()
+ this.ctx.arc(this.compatibilitySize(parseFloat(config.x)*this.scale+parseFloat(config.w)*this.scale/2), this.compatibilitySize(parseFloat(config.y)*this.scale+parseFloat(config.h)*this.scale/2), this.compatibilitySize(parseFloat(config.w)*this.scale/2), 0, 2 * Math.PI, false)
+ this.ctx.stroke();
+ this.ctx.clip()
+ }
+
+ await this.ctx.drawImage(image_url,this.compatibilitySize(parseFloat(config.x)*this.scale),this.compatibilitySize(parseFloat(config.y)*this.scale),this.compatibilitySize(parseFloat(config.w)*this.scale),this.compatibilitySize(parseFloat(config.h)*this.scale))
+ this.ctx.restore() //Restore previously saved drawing context
+ resolve()
+ }else{
+ let err_msg = "Links cannot be empty:101"
+ reject(err_msg)
+ }
+ })
+ },
+ /**
+ * base64 to native available path
+ * @param {Object} config
+ */
+ base64ToNative(config){
+ return new Promise((resolve,reject)=>{
+ let fileName = new Date().getTime()
+ var filePath = `${wx.env.USER_DATA_PATH}/${fileName}_rCanvas.png`
+ wx.getFileSystemManager().writeFile({
+ filePath: filePath,
+ data: config.url.replace(/^data:\S+\/\S+;base64,/, ''),
+ encoding: 'base64',
+ success: function() {
+ resolve(filePath)
+ },
+ fail: function(error) {
+ reject(error)
+ }
+ })
+ })
+ },
+ /**
+ * native url to base64
+ * @param {Object} config
+ */
+ urlToBase64(config){
+ return new Promise(async (resolve,reject)=>{
+ if (typeof window != 'undefined') {
+ await this.downLoadNetworkFile(config.url).then(res=>{ // two function
+ resolve(res)
+ }).catch(err=>{
+ reject(err)
+ })
+ }else if (typeof plus != 'undefined') {
+ plus.io.resolveLocalFileSystemURL(config.url,(obj)=>{
+ obj.file((file)=>{
+ let fileReader = new plus.io.FileReader()
+ fileReader.onload = (res)=>{
+ resolve(res.target.result)
+ }
+ fileReader.onerror = (err)=>{
+ reject(err)
+ }
+ fileReader.readAsDataURL(file)
+ }, (err)=>{
+ reject(err)
+ })
+ },(err)=>{
+ reject(err)
+ })
+ }else if(typeof wx != 'undefined'){
+ wx.getFileSystemManager().readFile({
+ filePath: config.url,
+ encoding: 'base64',
+ success: function(res) {
+ resolve('data:image/png;base64,' + res.data)
+ },
+ fail: function(error) {
+ reject(error)
+ }
+ })
+ }
+ })
+ },
+ setNativeBorderRadius(config){
+ let border_radius = config.border_radius?(parseFloat(config.border_radius)*this.scale):(20*this.scale)
+ if ((parseFloat(config.w)*this.scale) < 2 * border_radius) border_radius = (parseFloat(config.w)*this.scale) / 2;
+ if ((parseFloat(config.h)*this.scale) < 2 * border_radius) border_radius = (parseFloat(config.h)*this.scale) / 2;
+ this.ctx.beginPath();
+ this.ctx.moveTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + border_radius), this.compatibilitySize((parseFloat(config.y)*this.scale)));
+ this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize(border_radius));
+ this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize(border_radius));
+ this.ctx.arcTo((this.compatibilitySize(parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize(border_radius));
+ this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize(border_radius));
+ this.ctx.closePath();
+ this.ctx.strokeStyle = config.color || config.border_color || 'rgba(0,0,0,0)'; // 设置绘制边框的颜色
+ this.ctx.stroke();
+ this.ctx.save()
+ this.ctx.clip();
+
+ },
+ /**
+ * Download network file
+ * @param {Object} url : download url
+ */
+ downLoadNetworkFile(url){
+ return new Promise((resolve,reject)=>{
+ uni.downloadFile({
+ url,
+ success:(res)=>{
+ if(res.statusCode == 200){
+ resolve(res.tempFilePath)
+ }else{
+ reject("Download Image Fail:102")
+ }
+ },
+ fail:(err)=>{
+ reject("Download Image Fail:101")
+ }
+ })
+ })
+ },
+ /**
+ * Save image to natice
+ * @param {Object} filePath : native imageUrl
+ */
+ saveImage(filePath){
+ return new Promise((resolve,reject)=>{
+ if(!filePath){
+ reject("FilePath cannot be null:101")
+ return;
+ }
+
+ // #ifdef H5
+ var createA = document.createElement("a");
+ createA.download = filePath;
+ createA.href = filePath;
+ document.body.appendChild(createA);
+ createA.click();
+ createA.remove();
+ resolve()
+ // #endif
+
+ // #ifndef H5
+ uni.saveImageToPhotosAlbum({
+ filePath: filePath,
+ success:(res)=>{
+ resolve(res)
+ },
+ fail:(err)=>{
+ reject(err)
+ }
+ })
+ // #endif
+ })
+ }
+ }
+}
diff --git a/components/r-canvas/r-canvas.vue b/components/r-canvas/r-canvas.vue
new file mode 100644
index 0000000..5722790
--- /dev/null
+++ b/components/r-canvas/r-canvas.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/main.js b/main.js
index 6820ba3..3822e1d 100644
--- a/main.js
+++ b/main.js
@@ -12,6 +12,7 @@ let zaudio = new ZAudio({
Vue.prototype.$zaudio = zaudio
Vue.prototype.$dayjs = dayjs;
+Vue.prototype.$store = store;
import common from 'utils/common.js'
Vue.prototype.$noMultipleClicks = common.noMultipleClicks;
diff --git a/package-lock.json b/package-lock.json
index 48e341a..6ca7375 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,3 +1,49 @@
{
- "lockfileVersion": 1
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "base64-arraybuffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+ "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
+ },
+ "css-line-break": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz",
+ "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+ "requires": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "html2canvas": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
+ "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+ "requires": {
+ "css-line-break": "^2.1.0",
+ "text-segmentation": "^1.0.3"
+ }
+ },
+ "text-segmentation": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
+ "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+ "requires": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "utrie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
+ "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+ "requires": {
+ "base64-arraybuffer": "^1.0.2"
+ }
+ },
+ "wxml2canvas": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/wxml2canvas/-/wxml2canvas-1.0.1.tgz",
+ "integrity": "sha512-AdWvxgTjJtW/m6Cki1cwGO0HOERKU8O9V3RcCz8UyqJbrPF7e8Nv27/epYiIs64HlbPTKWTLl7ECjQi6UVducA=="
+ }
+ }
}
diff --git a/pages/mine/messageDetail.vue b/pages/mine/messageDetail.vue
index cfabcbf..016391c 100644
--- a/pages/mine/messageDetail.vue
+++ b/pages/mine/messageDetail.vue
@@ -1,7 +1,7 @@
- {{tit}}
-
+ {{ messageObj.title }}
+
@@ -9,55 +9,57 @@
\ No newline at end of file
+
diff --git a/pages/mine/reportExcel/weekReport.vue b/pages/mine/reportExcel/weekReport.vue
index 5944c94..9558cf4 100644
--- a/pages/mine/reportExcel/weekReport.vue
+++ b/pages/mine/reportExcel/weekReport.vue
@@ -2,23 +2,23 @@
- 避暑山庄数智工牌周报
- 01月24日~1月30日
+ {{ projectName || '' }}数智工牌周报
+ {{ weekObj.createTime | getTimeLine }}
- 生成时间:2022-01-27 22:00
+ 生成时间:{{ weekObj.createTime || '--' }}
-
-
+
+
@@ -26,123 +26,188 @@
-
+
- 接待量(次)
+ {{ data.name }}
- 0
+ {{ data.num || 0 }}
- 对比上周:0
- --
+ 对比上周: {{ data.preNum || 0 }}
+ {{ data.percent || '--' }}
+
+ {{ data.percent > 0 ? '↑' : '↓' }}
+
-
+
-
-
+
+
销讲场景执行排名
-
-
- 销讲场景平均执行对比上周下跌12%,其中【送客执行】最强为99%,【区位介绍】执行最弱为25%;
-
-
-
-
-
-
- 产品设计
-
- {{ (index+1)*10 }} %
-
-
-
+
+
+ 销讲场景平均执行对比上周
+ {{ rankTop('fractionPKName') }}
+ {{ rankTop('fractionPK') }}
+ %,其中【{{ rankTop('fractionBastName') }}】最强为
+ {{ rankTop('fractionBastValue') }}
+ %,【{{ rankTop('fractionLastName') }}】执行最弱为
+ {{ rankTop('fractionLastValue') }}
+ %;
+
+
+
+
+
+
+ {{ percent.title }}
+
+
+
+ {{ percent.value || '0' }} %
+
+
+
+
+
+
+ 暂无数据
+
+
-
+
接待统计
-
- 顾问平均执行率对比上周上升5人,下降3人,期中齐猛上升6%为最高,王楠下降-2%降幅最大。
-
-
-
-
-
- {{ head.title }}
-
-
+
+
+
+ 顾问平均执行率对比上周
+
+
+ {{ rankTop('ranktype') }}
+
+ {{ rankTop('people') }}
+
+ 人,其中{{ rankTop('topName') }}上升
+
+ {{ rankTop('topPk') }}
+
+ %为最高,{{ rankTop('lastName') }}下降
+
+ {{ rankTop('lastPk') }}
+
+ %降幅最大。
+
-
-
-
-
- 白课程
- 6
- 66m
- 71%
- +6%
-
-
+
+
+
+
+ {{ head.title }}
+
+
+
+
+
+
+
+ {{ data.name }}
+ {{ data.receptionCount }}
+ {{ data.avgDuration }}m
+ {{ data.fraction }}%
+
+ {{ data.pk > 0 ? `+${data.pk}` : data.pk }}%
+
+
+
+
-
-
- 查看全部
+
+
+
+
+ 暂无数据
-
+
-
+
顾问销讲执行率排名(TOP10)
-
-
-
-
-
- 产品设计
-
- {{ (index+1)*10 }} %
-
-
-
+
+
+
+
+
+ {{ percent.title }}
+
+
+
+
+ {{ percent.value || '0' }} %
+
+
+
+
+
+
+
+ 暂无数据
+
+
-
+
顾问接待量排名(TOP10)
-
-
-
-
-
- 产品设计
-
- {{ (index+1)*10 }} %
-
-
-
+
+
+
+
+
+
+ {{ percent.title }}
+
+
+
+
+ {{ percent.value || '0' }} %
+
+
+
+
+
+
+
+ 暂无数据
+
+
-
+
使用建议
-
@@ -154,27 +219,27 @@
执行率整体较低;
-
+
原因:整体平均执率低
- 建议: 1、精简话术(关键词、指标点);
- 2、对顾问进行话术培训。
+ 建议: 1、精简话术(关键词、指标点);
+ 2、对顾问进行话术培训。
-
+
-
+
@@ -184,8 +249,7 @@
export default {
data() {
return {
- tableHead: [
- {
+ tableHead: [{
title: '顾问',
style: {
flex: 1
@@ -216,10 +280,272 @@
}
},
],
- // list: []
+ id: '', // id
+
+ needList: ['JDLTop', 'ZXLTop', 'XJTop1'], // 需要转换数组的内容
+
+ // 简报
+ numlist: [{
+ name: '接待量 (次)',
+ num: '',
+ setName: 'receptionCount1',
+ percent: '',
+ percentName: 'receptionCountPK',
+ preNum: '', // 上周数量
+ preNumName: 'receptionCount2', //
+
+ }, {
+ name: '有效接待 (次)',
+ num: '',
+ setName: 'activeCustomer1',
+ percent: '',
+ percentName: 'activeCustomerPK',
+ preNum: '', // 上周数量
+ preNumName: 'receptionCount2', //
+ },
+ {
+ name: '平均执行率(%)',
+ num: '',
+ setName: 'fraction1',
+ percent: '',
+ percentName: 'fractionPK',
+ preNum: '', // 上周数量
+ preNumName: 'receptionCount2', //
+ },
+ {
+ name: '平均接待时长(分)',
+ num: '',
+ setName: 'avgDuration1',
+ percent: '',
+ percentName: 'avgDurationPK',
+ preNum: '', // 上周数量
+ preNumName: 'receptionCount2', //
+ },
+ {
+ name: '违禁接待 (次)',
+ num: '',
+ setName: 'prohibitedNum1',
+ percent: '',
+ percentName: 'prohibitedNumPK',
+ preNum: '', // 上周数量
+ preNumName: 'prohibitedNum2', //
+ },
+ {
+ name: '客户画像触达 (次)',
+ num: '',
+ setName: 'reachSum1',
+ percent: '',
+ percentName: 'reachSumPK',
+ preNum: '', // 上周数量
+ preNumName: 'reachSum2', //
+ },
+ {
+ name: '已标记',
+ num: '',
+ setName: 'labelledReceptionNum1',
+ percent: '',
+ percentName: 'labelledReceptionNumPK',
+ preNum: '', // 上周数量
+ preNumName: 'labelledReceptionNum2', //
+ },
+ {
+ name: '未标记',
+ num: '',
+ setName: 'unlabelledReceptionNum1',
+ percent: '',
+ percentName: 'unlabelledReceptionNumPK',
+ preNum: '', // 上周数量
+ preNumName: 'unlabelledReceptionNum2', //
+ },
+ ],
+
+ // 周报详情
+ weekObj: {},
+ projectName: '', // 项目名称
}
},
-
+
+
+ computed: {
+
+ // 排名最高与最低
+ rankTop() {
+ return name => {
+ let obj = {
+ ranktype: (this.weekObj.customerInfo1.length - this.weekObj.customerInfo2.length) > 0 ? '上升' : '下降',
+ people: Math.abs(this.weekObj.customerInfo1.length - this.weekObj.customerInfo2.length),
+ topName: this.weekObj.customerInfo1[0].name,
+ topPk: Math.abs(this.weekObj.customerInfo1[0].pk),
+ lastName: this.weekObj.customerInfo1[this.weekObj.customerInfo1.length-1].name,
+ lastPk: Math.abs(this.weekObj.customerInfo1[this.weekObj.customerInfo1.length-1].pk), //
+ class: (this.weekObj.customerInfo1.length - this.weekObj.customerInfo2.length) > 0 ? 'up' : 'down',
+ fractionPKName: this.weekObj.fractionPK > 0 ? '上涨' : '下跌',
+ fractionPK: Math.abs(this.weekObj.fractionPK),
+ fractionBastName: this.weekObj.XJTop1List[0].title,
+ fractionBastValue: this.weekObj.XJTop1List[0].value,
+ fractionLastName: this.weekObj.XJTop1List[this.weekObj.XJTop1List.length-1].title,
+ fractionLastValue: this.weekObj.XJTop1List[this.weekObj.XJTop1List.length-1].value,
+ }
+ return obj[name]
+ }
+ },
+ },
+
+ onLoad(option) {
+ if (option.id) this.id = option.id
+ this.getMessage()
+ console.log(this.rankTop(this.weekObj), '12312312312')
+ },
+
+
+ onShareAppMessage() {
+ return {
+ title: `${this.projectName}数智工牌周报`,
+ path: `/pages/mine/reportExcel/weekRepor?id=${this.id}`
+ }
+ },
+
+ methods: {
+
+ // 获取周报详情
+ getMessage() {
+ this.$u.get('/zkMessage/findByProjectId', {
+ id: this.id
+ }).then(res => {
+ console.log(res)
+ let data = JSON.parse(res.zkMessage.content)
+ console.log(data)
+ this.bubbleSort(data.customerInfo1, 'pk')
+ this.bubbleSort(data.customerInfo2, 'pk')
+ data.customerInfo1.reverse()
+ data.customerInfo2.reverse()
+ this.weekObj = {
+ ...res.zkMessage,
+ ...data
+ }
+ console.log(this.weekObj, 'this.weekObj')
+ this.projectName = res.projectName
+ this.numlist.forEach(item => {
+ if (data[item.setName]) {
+ item.num = data[item.setName]
+ }
+ if (data[item.percentName]) {
+ item.percent = data[item.percentName]
+ }
+ if (data[item.preNumName]) {
+ item.preNum = data[item.preNumName]
+ }
+ })
+ this.init()
+ }).catch(e => {
+ console.log(e)
+ })
+
+ },
+
+
+ // 把对象转成数组并在后续的步骤方便处理
+ init() {
+ console.log(this.weekObj, 'this.weekObj')
+ this.needList.forEach(item => {
+ if (this.weekObj[item] && Object.keys(this.weekObj[item]).length > 0) {
+ this.weekObj[item + 'List'] = [] // 销讲执行
+ for (let i in this.weekObj[item]) {
+ this.weekObj[item + 'List'].push({
+ title: i,
+ value: this.weekObj[item][i]
+ })
+ }
+ }
+ })
+ this.sortInitArr()
+ },
+
+ // 排序对象转换后的数组
+ sortInitArr() {
+ this.needList.forEach(item => {
+ if (this.weekObj[item + 'List']) {
+ this.bubbleSort(this.weekObj[item + 'List'])
+ }
+ })
+
+ this.reverseList()
+ },
+
+ // 反转数组
+ reverseList() {
+ this.needList.forEach(item => {
+ if (this.weekObj[item + 'List']) {
+ this.weekObj[item + 'List'].reverse()
+ }
+ })
+ },
+
+ // 冒泡排序
+ bubbleSort(arr, keys = 'value') {
+ for (let i = 0; i < arr.length - 1; i += 1) {
+ //通过 arr.length 次把第一位放到最后,完成排序
+ //-i是因为最后的位置是会动态改变的,当完成一次后,最后一位会变成倒数第二位
+ for (let j = 0; j < arr.length - 1 - i; j += 1) {
+ if (arr[j][keys] > arr[j + 1][keys]) {
+ const temp = arr[j];
+ arr[j] = arr[j + 1];
+ arr[j + 1] = temp;
+ }
+ }
+ }
+ },
+ },
+
+ filters: {
+ // 时间格式转换
+ fomatDate(date) {
+ if (!date) return '--'
+ let arr = date.split(' ')
+ let str = arr[0]
+ let result = str.split('-')
+ return `${result[1]}-${result[2]}`
+ },
+
+ // 转换时间
+ getTimeLine(date, type = 1) {
+ if (!date) return '--'
+ let time = new Date(date)
+ time.setDate(time.getDate() - 7)
+ let arr = date.split(' ')
+ let str = arr[0]
+ let result = str.split('-')
+
+ let m = (time.getMonth() + 1) < 10 ? `0${time.getMonth() + 1}` : (time.getMonth() + 1)
+ let d = time.getDate() < 10 ? `0${time.getDate()}` : time.getDate()
+
+ if (type == 1) {
+ return `${m}.${d}-${result[1]}.${result[2]}`
+ } else {
+ return `${m}月${d}日~${result[1]}月${result[2]}日`
+ }
+ },
+
+ // 设置颜色
+ setColor(value) {
+ let color = ''
+ switch(true) {
+ case 0 <= value && value <= 70 :
+ color = '#4FC78F';
+ break;
+ case 70 < value && value <= 80 :
+ color = '#FFCC00';
+ break;
+ case 80 < value && value <= 90 :
+ color = '#FF8C13';
+ break;
+ case 90 < value && value <= 100 :
+ color = '#E7483C';
+ break;
+ }
+ return color
+ },
+ }
}
@@ -230,17 +556,17 @@
display: flex;
flex-direction: column;
background: #F8F8F8;
-
+
.nav-header {
flex-shrink: 0;
}
-
+
.container {
padding: 30rpx 30rpx 0;
display: flex;
flex-direction: column;
background: #fff;
-
+
.c-head-card {
padding: 30rpx;
width: 100%;
@@ -250,13 +576,13 @@
box-shadow: 10rpx 10rpx #2671E2;
display: flex;
flex-direction: column;
-
+
.c-title-text {
position: relative;
flex-grow: 1;
font-size: 48rpx;
color: #303030;
-
+
.date {
position: absolute;
right: 0;
@@ -265,19 +591,19 @@
color: #303030;
}
}
-
+
.creative-time {
margin: 20rpx 0 0 0;
flex-shrink: 0;
}
}
}
-
-
-
+
+
+
.briefing {
margin: 40rpx 0 0 0;
-
+
.briefing-title {
padding: 0 30rpx;
height: 90rpx;
@@ -287,12 +613,12 @@
font-size: 32rpx;
font-weight: 600;
}
-
+
.briefing-box {
width: 100%;
display: flex;
flex-wrap: wrap;
-
+
.briefing-box-item {
padding: 20rpx 30rpx;
width: 50%;
@@ -300,70 +626,85 @@
border: 1px solid #E0E0E0;
border-left: none;
border-top: none;
-
+
&:nth-of-type(2n) {
border-right: none;
}
-
+
.top {
font-size: 28rpx;
}
-
+
.middle {
margin: 14rpx 0 12rpx;
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
-
+
.bottom {
font-size: 26rpx;
color: #666666;
-
+
.b-text {
margin-left: 20rpx;
+
+
+ &.down {
+ color: #43CD80;
+ font-size: 34rpx;
+ }
+
+ &.up {
+ font-size: 34rpx;
+ color: #E7483C;
+ }
}
}
}
}
}
-
-
+
+
.execution-ranking {
margin: 20rpx 0 0 0;
padding: 30rpx;
background: #fff;
-
+
.execution-ranking-title {
font-size: 32rpx;
font-weight: 500;
}
-
+
.execution-ranking-desc {
margin-top: 20rpx;
font-size: 30rpx;
}
-
+
.ranking-box {
margin: 30rpx 0 0 0;
+
.ranking-item {
margin-bottom: 18rpx;
display: flex;
-
+
&:nth-last-of-type(1) {
margin-bottom: 0;
}
-
+
.left {
flex-shrink: 0;
width: 140rpx;
font-size: 30rpx;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
-
+
.middle {
flex-grow: 1;
}
-
+
.right {
flex-shrink: 0;
width: 118rpx;
@@ -373,24 +714,24 @@
}
}
}
-
+
.statistics {
margin: 20rpx 0 0 0;
background: #fff;
-
+
.statistics-title {
padding: 30rpx 30rpx 0;
width: 100%;
}
-
+
.statistics-desc {
padding: 0 30rpx;
margin-top: 20rpx;
}
-
+
.table {
margin: 30rpx 0 0 0;
-
+
.thead {
padding: 0 30rpx;
width: 100%;
@@ -401,45 +742,52 @@
border-left: none;
border-right: none;
font-size: 26rpx;
-
+
.thead-item {
text-align: center;
}
}
-
+
.tbody {
-
+
.tbody-item {
padding: 0 30rpx;
display: flex;
align-items: center;
height: 72rpx;
background: #FAFCFF;
-
+
&:nth-of-type(2n) {
background: #FFFFFF;
}
-
+
.tbody-items {
flex: 1;
display: flex;
justify-content: center;
}
+ .name {
+ justify-content: flex-start;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
.time {
flex: 2;
}
-
+
.percent {
flex: 2;
}
-
+
.week {
flex: 1.5;
}
}
}
-
+
.tbottom {
width: 100%;
height: 72rpx;
@@ -452,43 +800,47 @@
}
}
}
-
+
.guwen-ranking {
margin: 20rpx 0 0 0;
width: 100%;
padding: 30rpx;
background: #fff;
-
+
.guwen-ranking-title {
font-size: 32rpx;
font-weight: 500;
}
-
+
.guwen-ranking-desc {
margin-top: 20rpx;
font-size: 30rpx;
}
-
+
.ranking-box {
margin: 30rpx 0 0 0;
+
.ranking-item {
margin-bottom: 18rpx;
display: flex;
-
+
&:nth-last-of-type(1) {
margin-bottom: 0;
}
-
+
.left {
flex-shrink: 0;
width: 140rpx;
font-size: 30rpx;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
-
+
.middle {
flex-grow: 1;
}
-
+
.right {
flex-shrink: 0;
width: 118rpx;
@@ -498,23 +850,24 @@
}
}
}
-
+
.proposal {
margin: 20rpx 0 0 0;
padding: 30rpx;
-
+ background: #fff;
+
.proposal-title {
font-size: 32rpx;
font-weight: 500;
}
-
+
.proposal-box {
margin: 30rpx 0 0 0;
-
+
.proposal-item {
margin: 20rpx 0 0 0;
display: flex;
-
+
.lside {
flex-shrink: 0;
margin: 0 12rpx 0 0;
@@ -526,28 +879,38 @@
line-height: 44rpx;
color: #fff;
}
-
+
.rside {
-
+
.rside-title {
font-size: 32rpx;
}
-
+
.rside-box {
margin: 16rpx 0 0 0;
}
}
}
}
-
+
}
-
+
.up {
color: #E6273A;
}
-
+
.down {
color: #43CD80;
}
+
+ .empity {
+ width: 100%;
+ height: 300rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 32rpx;
+ font-weight: 600;
+ }
}
-
\ No newline at end of file
+
diff --git a/static/libs/image-tools.js b/static/libs/image-tools.js
new file mode 100644
index 0000000..07fb5de
--- /dev/null
+++ b/static/libs/image-tools.js
@@ -0,0 +1,152 @@
+function getLocalFilePath(path) {
+ if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
+ return path
+ }
+ if (path.indexOf('file://') === 0) {
+ return path
+ }
+ if (path.indexOf('/storage/emulated/0/') === 0) {
+ return path
+ }
+ if (path.indexOf('/') === 0) {
+ var localFilePath = plus.io.convertAbsoluteFileSystem(path)
+ if (localFilePath !== path) {
+ return localFilePath
+ } else {
+ path = path.substr(1)
+ }
+ }
+ return '_www/' + path
+}
+
+export function pathToBase64(path) {
+ return new Promise(function(resolve, reject) {
+ if (typeof window === 'object' && 'document' in window) {
+ if (typeof FileReader === 'function') {
+ var xhr = new XMLHttpRequest()
+ xhr.open('GET', path, true)
+ xhr.responseType = 'blob'
+ xhr.onload = function() {
+ if (this.status === 200) {
+ let fileReader = new FileReader()
+ fileReader.onload = function(e) {
+ resolve(e.target.result)
+ }
+ fileReader.onerror = reject
+ fileReader.readAsDataURL(this.response)
+ }
+ }
+ xhr.onerror = reject
+ xhr.send()
+ return
+ }
+ var canvas = document.createElement('canvas')
+ var c2x = canvas.getContext('2d')
+ var img = new Image
+ img.onload = function() {
+ canvas.width = img.width
+ canvas.height = img.height
+ c2x.drawImage(img, 0, 0)
+ resolve(canvas.toDataURL())
+ canvas.height = canvas.width = 0
+ }
+ img.onerror = reject
+ img.src = path
+ return
+ }
+ if (typeof plus === 'object') {
+ plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
+ entry.file(function(file) {
+ var fileReader = new plus.io.FileReader()
+ fileReader.onload = function(data) {
+ resolve(data.target.result)
+ }
+ fileReader.onerror = function(error) {
+ reject(error)
+ }
+ fileReader.readAsDataURL(file)
+ }, function(error) {
+ reject(error)
+ })
+ }, function(error) {
+ reject(error)
+ })
+ return
+ }
+ if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
+ wx.getFileSystemManager().readFile({
+ filePath: path,
+ encoding: 'base64',
+ success: function(res) {
+ resolve('data:image/png;base64,' + res.data)
+ },
+ fail: function(error) {
+ reject(error)
+ }
+ })
+ return
+ }
+ reject(new Error('not support'))
+ })
+}
+
+export function base64ToPath(base64, extName) {
+ return new Promise(function(resolve, reject) {
+ if (typeof window === 'object' && 'document' in window) {
+ base64 = base64.split(',')
+ var type = base64[0].match(/:(.*?);/)[1]
+ var str = atob(base64[1])
+ var n = str.length
+ var array = new Uint8Array(n)
+ while (n--) {
+ array[n] = str.charCodeAt(n)
+ }
+ return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], { type: type })))
+ }
+ var fileName;
+ if (!extName) {
+ extName = base64.match(/data\:\S+\/(\S+);/)
+ if (extName) {
+ extName = extName[1]
+ } else {
+ reject(new Error('base64 error'))
+ }
+ fileName = Date.now() + '.' + extName;
+ } else {
+ fileName = Date.now() + extName;
+ }
+ if (typeof plus === 'object') {
+ var bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
+ bitmap.loadBase64Data(base64, function() {
+ var filePath = '_doc/uniapp_temp/' + fileName
+ bitmap.save(filePath, {}, function() {
+ bitmap.clear()
+ resolve(filePath)
+ }, function(error) {
+ bitmap.clear()
+ reject(error)
+ })
+ }, function(error) {
+ bitmap.clear()
+ reject(error)
+ })
+ return
+ }
+ if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
+ var filePath = wx.env.USER_DATA_PATH + '/' + fileName
+ wx.getFileSystemManager().writeFile({
+ filePath: filePath,
+ data: base64.replace(/^data:\S+\/\S+;base64,/, ''),
+ encoding: 'base64',
+ success: function() {
+ resolve(filePath)
+ },
+ fail: function(error) {
+ reject(error)
+ }
+ })
+ return
+ }
+ reject(new Error('not support'))
+ })
+}
\ No newline at end of file
diff --git a/store/index.js b/store/index.js
index ee53307..3ebf265 100644
--- a/store/index.js
+++ b/store/index.js
@@ -6,9 +6,16 @@ Vue.use(Vuex)
export default new Vuex.Store({
state: {
bgAudioMannager: null,
+
+ messageObj: {} , // 用户信息
},
mutations: {
+ // 日报详情
+ setMessageObj(state, obj) {
+ state.messageObj = obj
+ },
+
createAudio(state) {
state.bgAudioMannager = uni.getBackgroundAudioManager();
},
diff --git a/utils/domain.js b/utils/domain.js
index 3b37202..512ef1a 100644
--- a/utils/domain.js
+++ b/utils/domain.js
@@ -1,17 +1,6 @@
// http.js使用域名
-// const baseUrl = 'http://192.168.31.57:8080/autoSR/api';// 本地
-// const baseUrl = 'http://127.0.0.1:8080/api';// 本地
-// const baseUrl = 'http://121.42.63.138:9091/autoSR/api';// 测试站
-// const baseUrl = 'http://192.168.31.89:9090/api';// sh
-// const baseUrl = 'http://121.42.63.138:9091/autoSR/api';// 测试站
-// const baseUrl = 'http://192.168.31.92:8080/api';// 测试站
-// const baseUrl = 'http://127.0.0.1:8080/autoSR/api';// 本地
-// const baseUrl = 'http://192.168.31.244:8080/autoSR/api';// 本地
-const baseUrl = 'http://81.70.55.170:9090/autoSR/api';// 测试站
+const baseUrl = 'http://81.70.55.170:9090/autoSR/api';// 最新测试
// const baseUrl = 'http://192.168.31.210:8080/api'; // 泽明
-// const baseUrl = 'http://192.168.31.167:8080/autoSR/api'; // 长龙
-// const baseUrl = 'http://192.168.31.134:8080/autoSR/api'; // 佳豪
-// const baseUrl = 'http://10.2.1.104:8081/autoSR/api'; // 刘敏
// const baseUrl = 'https://zkgj.quhouse.com/api'; // 质控正式
// const baseUrl = 'https://hfju.com/api'; // 数智正式