From c00453f2731bdd509d38db58cb5c5951d28670f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=B9=E8=BE=89?= <814457906@qq.com> Date: Fri, 3 Mar 2023 10:04:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/integral/index.js | 12 +- components/r-canvas/r-canvas.js | 735 ++++++++++++++++++++++ components/r-canvas/r-canvas.vue | 26 + package.json | 17 +- pages.json | 14 +- pages/CommodityOrder/CommodityOrder.vue | 42 +- pages/Healthknowledge/Healthknowledge.vue | 13 +- pages/Personal/Personal.vue | 12 +- pages/homepage/homepage.vue | 10 +- pages/integral/integral.vue | 631 ++++++++++++++++++- 10 files changed, 1442 insertions(+), 70 deletions(-) create mode 100644 components/r-canvas/r-canvas.js create mode 100644 components/r-canvas/r-canvas.vue diff --git a/api/integral/index.js b/api/integral/index.js index f341f0a..206c1d3 100644 --- a/api/integral/index.js +++ b/api/integral/index.js @@ -18,10 +18,18 @@ export function selectPatientSignIn(patientId) { } //可兑换商品 - -export function selectExchangeGoods(pageNum,pageSize) { +export function selectExchangeGoods(pageNum, pageSize) { return request({ url: `/nurseApplet/patientInfo/selectExchangeGoods?pageNum=${pageNum}&pageSize=${pageSize}`, method: 'get' }) } + +//兑换 +export function integralGoodsOrder(data) { + return request({ + url: `/nurseApplet/patientInfo/integralGoodsOrder`, + method: 'post', + data + }) +} diff --git a/components/r-canvas/r-canvas.js b/components/r-canvas/r-canvas.js new file mode 100644 index 0000000..256a23d --- /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/package.json b/package.json index bbd71fa..b4155c7 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,16 @@ { - "dependencies": { - "uview-ui": "^1.8.4" - } + "dependencies": { + "uview-ui": "^1.8.4" + }, + "id": "r-canvas", + "name": "海报生成,随心所欲绘制样式,原生canvas方法的二次封装,自定义函数,持续更新", + "version": "1.3.1", + "description": "图片不失帧,保留原有画质,canvas方法扩展,暴露原生实例,可自行扩展,最好用的canvas插件", + "keywords": [ + "canvas", + "画布生成图片", + "绘制图片", + "商品海报", + "朋友圈海报" + ] } diff --git a/pages.json b/pages.json index 9257993..689c477 100644 --- a/pages.json +++ b/pages.json @@ -4,19 +4,19 @@ }, "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages { - "path": "pages/integral/integral", - "style": { - "navigationBarTitleText": "积分", - "enablePullDownRefresh": false, - "navigationBarBackgroundColor": "#ffffff" - } - },{ "path": "pages/startup/startup", "style": { "navigationBarTitleText": "", "navigationStyle": "custom" } },{ + "path": "pages/integral/integral", + "style": { + "navigationBarTitleText": "积分", + "enablePullDownRefresh": false, + "navigationBarBackgroundColor": "#ffffff" + } + }, { "path": "pages/information/information", "style": { "navigationBarTitleText": "完善个人信息", diff --git a/pages/CommodityOrder/CommodityOrder.vue b/pages/CommodityOrder/CommodityOrder.vue index a270278..bcf3f10 100644 --- a/pages/CommodityOrder/CommodityOrder.vue +++ b/pages/CommodityOrder/CommodityOrder.vue @@ -25,15 +25,25 @@ {{item.goodsName}} - ¥{{item.goodsPrice}} + ¥{{item.goodsPrice}} 型号:{{item.goodsAttributeName}} ×{{item.goodsCount}} - 实付款: - ¥{{item.totalPrice}} + + 实付款: + + + 实付: + + ¥{{item.totalPrice}} + {{item.integralExchangeSill}} + + 积分 + @@ -74,7 +84,7 @@ 共1件 - 为了保证你的售后权益,请收到商品确认无误后再确认收货 + 为了保证您的售后权益,请收到商品确认无误后再确认收货 确定 @@ -252,20 +262,16 @@ this.pageNum = 1; this.baseurl = baseurl; let that = this - try { - const value = uni.getStorageSync('openid'); - if (value) {} else { - uni.navigateTo({ - url: '/pages/login/login' - }) - } - } catch (e) {} - try { - const value3 = uni.getStorageSync('Refresh'); - if (value3) { - that.goodsOrderinfo(); - } - } catch (e) {} + const value = uni.getStorageSync('openid'); + if (value) {} else { + uni.navigateTo({ + url: '/pages/login/login' + }) + } + const value3 = uni.getStorageSync('Refresh'); + if (value3) { + that.goodsOrderinfo(); + } }, onLoad(options) { //开局调用 let that = this diff --git a/pages/Healthknowledge/Healthknowledge.vue b/pages/Healthknowledge/Healthknowledge.vue index 0631d83..3d357e9 100644 --- a/pages/Healthknowledge/Healthknowledge.vue +++ b/pages/Healthknowledge/Healthknowledge.vue @@ -148,7 +148,7 @@ .item { width: 100%; - height: 200rpx; + height: 250rpx; position: relative; border-bottom: 2rpx solid #CDC9C9; @@ -157,8 +157,8 @@ right: 0; top: 50%; transform: translateY(-50%); - width: 253rpx; - height: 164rpx; + width: 200rpx; + height: 200rpx; border-radius: 10rpx; } @@ -176,6 +176,13 @@ left: 0; width: 60%; font-size: 30rpx; + text-overflow: -o-ellipsis-lastline; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 5; //行数需设置 + line-clamp: 5; + -webkit-box-orient: vertical; } } } diff --git a/pages/Personal/Personal.vue b/pages/Personal/Personal.vue index f6191c6..1e6259a 100644 --- a/pages/Personal/Personal.vue +++ b/pages/Personal/Personal.vue @@ -34,15 +34,21 @@ 积分 - {{appPersonallist.integral}} + + {{appPersonallist.integral}} + + 0 优惠券 - - {{appPersonallist.patientCouponCount}}张 + + {{appPersonallist.patientCouponCount}} + + 0 diff --git a/pages/homepage/homepage.vue b/pages/homepage/homepage.vue index 12ed3de..55f5dd8 100644 --- a/pages/homepage/homepage.vue +++ b/pages/homepage/homepage.vue @@ -372,9 +372,13 @@ left: 0; width: 65%; font-size: 30rpx; - // overflow: hidden; - // text-overflow: ellipsis; - // white-space: nowrap; + text-overflow: -o-ellipsis-lastline; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 5; //行数需设置 + line-clamp: 5; + -webkit-box-orient: vertical; } } } diff --git a/pages/integral/integral.vue b/pages/integral/integral.vue index 4c2f30b..e6fc9d5 100644 --- a/pages/integral/integral.vue +++ b/pages/integral/integral.vue @@ -31,19 +31,19 @@ {{item.goodsName}} - {{item.attributeDetailsName}} + {{item.integralExchangeCount}}{{item.goodsUnit}} 需使用 {{item.integralExchangeSill}} 积分兑换 - + 立即兑换 - + 获取方式 @@ -77,18 +77,82 @@ {{list.inviteFriends}}积分 - + 去完成 - - - + + + + + + + + + + {{goodsitem.goodsName}} + + + 暂无 + + + + {{goodsitem.integralExchangeSill}}积分 + + + + 库存数量:{{goodsitem.goodsStock}} + + + + + + + {{updata.receiver}},{{updata.phone}} + + + {{updata.receiveAddress}} + + + 前往完善个人信息 + + + + + + + + + 商品规格 + + + + + + {{goodsitem.integralExchangeCount}}{{goodsitem.goodsUnit}} + + + + + + 立即兑换 + + + + + + + 保存到相册 + + + 分享给好友 + + @@ -96,46 +160,309 @@ import { signIn, selectPatientSignIn, - selectExchangeGoods + selectExchangeGoods, + integralGoodsOrder } from '@/api/integral/index.js' import { inviteFriends } from '@/api/Personal/Personal.js'; + import { + goodPatientInfo + } from '@/api/modifyAddress/modifyAddress.js'; import baseurl from '../../api/baseurl'; + import rCanvas from "@/components/r-canvas/r-canvas.vue" export default { - + components: { + rCanvas + }, data() { return { - integral: 0, - gainshow: false, - yaoqingshow: false, + baseurl: '', patientId: null, + integral: 0, + gainshow: false, //积分邀请 + buyshow: false, //兑换购买 + yaoqingshow: false, + yaoqingimg: null, list: null, - inviteimg: null, + inviteimg: null, //邀请二维码 pageNum: 1, pageSize: 10, goodstotal: 0, goodslist: null, + goodsitem: null, + userid: null, + updata: { + "orderChannel": 'WECHAT_APPLET', + "originalTotalPrice": null, + "integralExchangeSill": null, + "integralExchangeCount": null, + "orderType": "INTEGRAL_EXCHANGE", + "buySource": "SHOPPING_MALL", + "integralDeductionCount": null, + "attributeDetailsId": null, + "discountPrice": null, + "giveIntegral": null, + "goodsAttributeContent": null, + "goodsAttributeDetailsId": null, + "goodsAttributeId": null, + "goodsAttributeName": null, + "goodsCount": null, + "goodsName": null, + "goodsPrice": null, + "goodsStock": null, + "nurseStationId": null, + "patientId": null, + "phone": "18963146613", + "receiveAddress": null, + "receiver": null, + } }; - }, - onReady() { - }, onLoad(options) { + this.baseurl = baseurl this.integral = options.integral var that = this this.selectExchangeGoodsinfo(); const value = uni.getStorageSync('patientId'); if (value) { that.patientId = value + that.updata.patientId = value that.selectPatientSignInifo(); - inviteFriends(value).then(res => { - that.inviteimg = res.msg - }) + that.goodsList(); } }, + onShow() { + var that = this + this.baseurl = baseurl + const value = uni.getStorageSync('patientId'); + if (value) { + that.updata.patientId = value + goodPatientInfo(value).then(res => { + if (res.code == 200) { + var user = res.data.filter(e => e.id == that.userid) + if (user.length >= 1) { + that.updata.receiver = user[0].receiveName + that.updata.receiveAddress = user[0].areaName + user[0].receiveAddress + that.updata.phone = user[0].receivePhone + that.userid = user[0].id + } else { + that.updata.receiver = res.data[0].receiveName + that.updata.receiveAddress = res.data[0].areaName + res.data[0].receiveAddress + that.updata.phone = res.data[0].receivePhone + that.userid = res.data[0].id + } + } + }) + } else {} + let useritem = null + uni.$on('updata', function(data) { + if (data.useritem) { + useritem = JSON.parse(data.useritem) + that.updata.receiver = useritem.receiveName + that.updata.phone = useritem.receivePhone + that.updata.receiveAddress = useritem.areaName + useritem.receiveAddress + that.userid = useritem.id + } + }) + }, methods: { - yaoqingshowfalse() {}, + yaoqingshowtrue() { + this.yaoqingshow = true + this.$nextTick(async () => { + await inviteFriends(this.patientId).then(res => { + this.inviteimg = res.msg + }) + uni.showLoading({ + title: '加载中' + }); + // 初始化 + await this.$refs.rCanvas.init({ + canvas_id: "rCanvas" + }) + // 画图 + await this.$refs.rCanvas.drawImage({ + url: "/static/yaoqinghaoyou.png", + x: 0, + y: 0, + w: 330, + h: 600 + }).catch(err_msg => { + uni.showToast({ + title: err_msg, + icon: "none" + }) + }) + await this.$refs.rCanvas.drawImage({ + url: baseurl + this.inviteimg, + x: 100, + y: 370, + w: 130, + h: 130 + }).catch(err_msg => { + uni.showToast({ + title: err_msg, + icon: "none" + }) + }) + // 画文字 + await this.$refs.rCanvas.drawText({ + text: "智慧康养泉城,医护关怀到家", + x: 165, + y: 330, + font_color: "#444444", + font_size: 12, + font_weight: 600, + text_align: 'center' + }).catch(err_msg => { + uni.showToast({ + title: err_msg, + icon: "none" + }) + }) + await this.$refs.rCanvas.drawText({ + text: "超多福利,快来体验吧!", + x: 165, + y: 350, + font_color: "#444444", + font_size: 12, + font_weight: 600, + text_align: 'center' + }).catch(err_msg => { + uni.showToast({ + title: err_msg, + icon: "none" + }) + }) + await this.$refs.rCanvas.drawText({ + text: "泉医到家小程序", + x: 165, + y: 530, + font_color: "#444444", + font_size: 10, + text_align: 'center' + }).catch(err_msg => { + uni.showToast({ + title: err_msg, + icon: "none" + }) + }) + await this.$refs.rCanvas.drawText({ + text: "(长按识别二维码开启健康之旅)", + x: 165, + y: 543, + font_color: "#444444", + font_size: 7, + text_align: 'center' + }).catch(err_msg => { + uni.showToast({ + title: err_msg, + icon: "none" + }) + }) + // 生成海报 + await this.$refs.rCanvas.draw((res) => { + this.yaoqingimg = res.tempFilePath + uni.hideLoading(); + //res.tempFilePath:生成成功,返回base64图片 + // 保存图片 + // this.$refs.rCanvas.saveImage(res.tempFilePath) + }) + }) + }, + //保存 + draw() { + // 保存图片 + this.$refs.rCanvas.saveImage(this.yaoqingimg).then(res => { + uni.showToast({ + title: '保存成功', + duration: 2000 + }); + }).catch(err => { + uni.showToast({ + icon: 'error', + title: '保存失败', + duration: 2000 + }); + }) + }, + //分享 + fenx() { + wx.showShareImageMenu({ + path: this.yaoqingimg, + }) + }, + yaoqingshowfalse() { + this.yapqingshow = false; + this.$nextTick(async () => { + await this.$refs.rCanvas.clearCanvas((res) => { + console.log(res) + }) + await this.$refs.rCanvas.setCanvasWidth(0) + await this.$refs.rCanvas.setCanvasHeight(0) + }) + }, + //兑换 + upbuy() { + integralGoodsOrder(this.updata).then(res => { + if (res.code == 200) { + this.$refs.uToast.show({ + title: '兑换商品成功', + type: 'success' + }) + this.buyshow = false + } else { + this.$refs.uToast.show({ + title: '兑换商品失败', + type: 'error' + }) + } + }) + }, + //跳转到全部收货地址 + upaddress() { + if (this.updata.receiver) { + uni.navigateTo({ + url: `/pages/modifyAddress/modifyAddress?updata=${JSON.stringify(this.updata)}` + }) + } else { + const value = uni.getStorageSync('openid'); + const value2 = uni.getStorageSync('patientId'); + if (value && value2) { + uni.navigateTo({ + url: '/pages/information/information' + }) + } else { + this.$refs.uToast.show({ + title: '未登录,请先登录', + type: 'error' + }) + if (this.timer) { + clearTimeout(this.timer) + } + this.timer = setTimeout(e => { + uni.navigateTo({ + url: '/pages/login/login' + }) + }, 1500) + } + } + }, + ///兑换 + buyshowtrue(item) { + this.buyshow = true + this.goodsitem = item + this.updata.goodsAttributeName = this.goodsitem.attributeDetailsName + this.updata.goodsAttributeId = this.goodsitem.goodsAttributeId + this.updata.goodsAttributeDetailsId = this.goodsitem.attributeDetailsId + this.updata.integralExchangeSill = this.goodsitem.integralExchangeSill + this.updata.integralExchangeCount = this.goodsitem.integralExchangeCount + this.updata.originalTotalPrice = 0 + this.updata.goodsStock = this.goodsitem.goodsStock + this.updata.goodsName = this.goodsitem.goodsName + this.updata.goodsPrice = this.goodsitem.goodsPrice + this.updata.goodsCount = 1 + }, //可兑换商品 selectExchangeGoodsinfo() { selectExchangeGoods(this.pageNum, this.pageSize).then(res => { @@ -165,6 +492,23 @@ } }) }, + // 收件人 + goodsList() { + goodPatientInfo(this.patientId).then(res => { + var list = res.data.filter(e => e.defaultAddressFlag == 1) + if (list.length >= 1) { + this.updata.receiver = list[0].receiveName + this.updata.receiveAddress = list[0].areaName + list[0].receiveAddress + this.updata.phone = list[0].receivePhone + this.userid = list[0].id + } else { + this.updata.receiver = res.data[0].receiveName + this.updata.receiveAddress = res.data[0].areaName + res.data[0].receiveAddress + this.updata.phone = res.data[0].receivePhone + this.userid = res.data[0].id + } + }) + }, }, onReachBottom() { //下滑加载 if (this.goodslist.length >= this.goodstotal) {} else { @@ -189,21 +533,246 @@