12
Showing
15 changed files
with
1111 additions
and
71 deletions
| ... | @@ -5,10 +5,69 @@ | ... | @@ -5,10 +5,69 @@ |
| 5 | <router-link to="/about">About</router-link> | 5 | <router-link to="/about">About</router-link> |
| 6 | </div>--> | 6 | </div>--> |
| 7 | <router-view /> | 7 | <router-view /> |
| 8 | |||
| 9 | <biz-model v-model="shareModel"></biz-model> | ||
| 8 | </div> | 10 | </div> |
| 9 | </template> | 11 | </template> |
| 10 | 12 | ||
| 11 | 13 | ||
| 14 | <script> | ||
| 15 | let urls = { | ||
| 16 | share: "/jiajiaCHApi/app/works/share" | ||
| 17 | }; | ||
| 18 | |||
| 19 | import BizModel from "@/components/biz-model/biz-model"; | ||
| 20 | import { httpPost } from "@/api/fetch-api"; | ||
| 21 | |||
| 22 | export default { | ||
| 23 | data() { | ||
| 24 | return { | ||
| 25 | shareModel: { | ||
| 26 | show: false, | ||
| 27 | title: "", | ||
| 28 | content: "", | ||
| 29 | index: "default", | ||
| 30 | btnShow: false, | ||
| 31 | btnText: "", | ||
| 32 | confirmHandler: null, | ||
| 33 | labelBtnShow: false, | ||
| 34 | labelBtnText: "", | ||
| 35 | labelBtnHandler: null | ||
| 36 | } | ||
| 37 | }; | ||
| 38 | }, | ||
| 39 | methods: { | ||
| 40 | init() { | ||
| 41 | // alert("init"); | ||
| 42 | // as.appSuccess = this.shareSuccessHandler; | ||
| 43 | // as.success = this.shareSuccessHandler; | ||
| 44 | }, | ||
| 45 | shareSuccessHandler() { | ||
| 46 | httpPost({ url: urls.share, data: { worksCode: "" } }).then(res => { | ||
| 47 | if (res == 1) { | ||
| 48 | let that = this; | ||
| 49 | this.shareModel.show = true; | ||
| 50 | this.shareModel.title = "分享成功"; | ||
| 51 | this.shareModel.content = "您已获得一次抽奖机会"; | ||
| 52 | this.shareModel.btnShow = true; | ||
| 53 | this.shareModel.btnText = "前往抽奖"; | ||
| 54 | this.shareModel.confirmHandler = function() { | ||
| 55 | that.$router.push("/draw"); | ||
| 56 | }; | ||
| 57 | this.shareModel.labelBtnShow = false; | ||
| 58 | } | ||
| 59 | }); | ||
| 60 | } | ||
| 61 | }, | ||
| 62 | created() { | ||
| 63 | this.init(); | ||
| 64 | }, | ||
| 65 | components: { | ||
| 66 | BizModel | ||
| 67 | } | ||
| 68 | }; | ||
| 69 | </script> | ||
| 70 | |||
| 12 | <style lang="scss"> | 71 | <style lang="scss"> |
| 13 | @import "./styles/support.scss"; | 72 | @import "./styles/support.scss"; |
| 14 | 73 | ||
| ... | @@ -136,7 +195,6 @@ body { | ... | @@ -136,7 +195,6 @@ body { |
| 136 | } | 195 | } |
| 137 | } | 196 | } |
| 138 | 197 | ||
| 139 | |||
| 140 | .home { | 198 | .home { |
| 141 | position: relative; | 199 | position: relative; |
| 142 | text-align: center; | 200 | text-align: center; | ... | ... |
| ... | @@ -20,7 +20,8 @@ let wxOauthUrl = global_wx_oauth_url; | ... | @@ -20,7 +20,8 @@ let wxOauthUrl = global_wx_oauth_url; |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | let whileList = [ | 22 | let whileList = [ |
| 23 | "https://api.k.wxpai.cn/bizproxy/kdapi/file/upload" | 23 | "https://api.k.wxpai.cn/bizproxy/kdapi/file/upload", |
| 24 | "https://api.k.wxpai.cn/bizproxy/kdapi/file/uploadBase64" | ||
| 24 | ] | 25 | ] |
| 25 | // let base = COM.baseUrl; | 26 | // let base = COM.baseUrl; |
| 26 | 27 | ||
| ... | @@ -133,9 +134,12 @@ export const store = { | ... | @@ -133,9 +134,12 @@ export const store = { |
| 133 | localStorage.removeItem("_jiajia_childrenhost_sesson"); | 134 | localStorage.removeItem("_jiajia_childrenhost_sesson"); |
| 134 | }, | 135 | }, |
| 135 | saveRedirectUrl() { | 136 | saveRedirectUrl() { |
| 136 | let current = Router.history.current || {}; | 137 | if (!Router.history.current || !Router.history.current.path) { |
| 138 | return; | ||
| 139 | } | ||
| 140 | let current = Router.history.current; | ||
| 137 | let data = { | 141 | let data = { |
| 138 | route: current.path, | 142 | route: current.path == "/" ? "/index" : current.path, |
| 139 | params: current.query | 143 | params: current.query |
| 140 | } | 144 | } |
| 141 | localStorage.setItem("_jiajia_childrenhost_redirect", JSON.stringify(data)); | 145 | localStorage.setItem("_jiajia_childrenhost_redirect", JSON.stringify(data)); |
| ... | @@ -152,6 +156,9 @@ export const store = { | ... | @@ -152,6 +156,9 @@ export const store = { |
| 152 | if (dataStr) { | 156 | if (dataStr) { |
| 153 | let data = JSON.parse(dataStr); | 157 | let data = JSON.parse(dataStr); |
| 154 | let path = data.route; | 158 | let path = data.route; |
| 159 | if (!path) { | ||
| 160 | return "/index"; | ||
| 161 | } | ||
| 155 | let sep = "?"; | 162 | let sep = "?"; |
| 156 | if (data.params) { | 163 | if (data.params) { |
| 157 | for (let key in data.params) { | 164 | for (let key in data.params) { |
| ... | @@ -161,7 +168,7 @@ export const store = { | ... | @@ -161,7 +168,7 @@ export const store = { |
| 161 | } | 168 | } |
| 162 | return path; | 169 | return path; |
| 163 | } | 170 | } |
| 164 | return null; | 171 | return "/index"; |
| 165 | }, | 172 | }, |
| 166 | delRedirectUrl() { | 173 | delRedirectUrl() { |
| 167 | localStorage.removeItem("_jiajia_childrenhost_redirect"); | 174 | localStorage.removeItem("_jiajia_childrenhost_redirect"); | ... | ... |
| ... | @@ -81,6 +81,202 @@ | ... | @@ -81,6 +81,202 @@ |
| 81 | </div> | 81 | </div> |
| 82 | </div> | 82 | </div> |
| 83 | 83 | ||
| 84 | <!-- 用户协议--> | ||
| 85 | <div class="model rule-model" v-if="data.index == 'agreement'"> | ||
| 86 | <div class="model-close" @click="modelCloseHandler"></div> | ||
| 87 | <div class="model-content"> | ||
| 88 | <div class="model-head-line"></div> | ||
| 89 | <div class="model-title">用户协议</div> | ||
| 90 | <div class="text-container"> | ||
| 91 | <div>“立乐家会员服务”(以下简称本服务)是由广州立白企业集团有限公司的官方微信公众号“立乐家”向广大用户提供的会员专享服务。本协议由您和广州立白企业集团有限公司(以下简称本公司)共同签订。</div> | ||
| 92 | <div>一、声明与承诺</div> | ||
| 93 | <div>(一)您确认,在您注册成为立乐家会员之前,你已充分阅读、理解并接受本协议的全部内容,一旦您使用本服务,即表示您同意遵循本协议之所有约定。</div> | ||
| 94 | <div>(二)您同意,本公司有权随时对本协议内容进行单方面的变更,并在官方微信公众号“立乐家”上予以公布,无需另行单独通知您;若您在本协议内容公告变更后继续使用本服务的,表示您已充分阅读、理解并接受修改后的协议内容,也将遵循修改后的协议内容使用本服务;若您不同意修改后的协议内容,您应停止使用本服务。</div> | ||
| 95 | <div>(三)您声明,在您同意接受本协议并成为立乐家会员时,您是具有中华人民共和国法律规定的完全民事行为能力,能够独立承担法律责任的自然人;未满18周岁的,您只能在父母或监护人的监护参与下使用,本协议内容不受您所属国家或地区的排斥。不具备前述条件的,您应立即终止注册或停止使用本服务。</div> | ||
| 96 | <div>二、立乐家会员概要</div> | ||
| 97 | <div>(一)“立乐家会员”:凭此会员身份,您拥有唯一编号及可以修改您的个人信息,并用以查询或计量您的积分以及享受相关优惠。</div> | ||
| 98 | <div>(二)会员服务:本公司向您提供的会员服务包含:</div> | ||
| 99 | <div>1.积分累积:在官方微信公众号进行登录、签到、抽奖等任务即可获得积分。</div> | ||
| 100 | <div>2.积分兑换:在微信公众号“立乐家”的积分商城中,可用积分兑换指定产品或服务。</div> | ||
| 101 | <div>3. 积分换购:在立乐家积分商城中,可用指定积分额度加钱换购指定产品或服务。</div> | ||
| 102 | <div></div> | ||
| 103 | <div>4.会员活动和折扣优惠:立白会员可以在会员日享受会员专享福利及折扣优惠;在您注册信息所填写的生日当天可获得额外生日专享积分;在指定日享受积分升值、特殊任务额外送积分等优惠。</div> | ||
| 104 | <div>5.使用积分兑换、换购的服务和产品作退货或不签收处理时,兑换、换购的积分将不被退回。</div> | ||
| 105 | <div>6.积分查询:在您成功注册成为立乐家会员后,您可以在微信端进入立白立乐家会员的会员主页(通过关注微信公众号“立乐家”并点击菜单中的会员中心)查询您的会员积分总量和记录,会员积分记录会即时更新。积分信息以系统登记为准,如您对积分记录有疑问,可以关注微信公众号“立乐家”并点击菜单中客服进行反馈,客服人员将会协助您核实您的积分记录。</div> | ||
| 106 | <div>7.服务异常处理:您使用本服务时,可能由于不可抗力因素造成本服务无法提供;您需确保您所输入的资料无误,如果因资料错误造成本公司无法及时与您联系的,本公司不承担任何损害赔偿责任。</div> | ||
| 107 | <div>8.您同意,本公司可以基于运营和安全的需要暂时停止提供、限制会员的部分功能或提供新的功能。在任何功能减少、增加或者变化时,只要您仍然使用本服务,表示您同意本协议或者变更后的协议。</div> | ||
| 108 | <div>三、立乐家会员账户</div> | ||
| 109 | <div>(一)注册相关</div> | ||
| 110 | <div>您同意:</div> | ||
| 111 | <div>1.同一用户只可以注册一次立乐家会员,同一微信用户、同一手机号视为同一用户。</div> | ||
| 112 | <div>2.您需要在注册时向本公司提供准确真实的资料,本公司在取得该信息后及时更新您的正确、最新及完整的资料。若有合理理由怀疑您提供的资料错误、不实、过时或不完整的,本公司有权暂停或终止向您提供部分或全部的会员服务,本公司对此不承担任何责任。</div> | ||
| 113 | <div>3.因您未及时更新资料,导致本服务无法提供或提供时发生任何错误,所引起产生的优惠及积分相关损失由用户自行承担,本公司不承担任何责任。</div> | ||
| 114 | <div>4.您应对您的立乐家会员账户(包括账户号码和代表账户的二维码)负责,您的会员账户仅限您本人使用,该账户不可转让、不可赠与、不可继承。</div> | ||
| 115 | <div>(二)账户安全</div> | ||
| 116 | <div>您将对使用该账户进行的一切操作及言论负完全的责任,您同意:</div> | ||
| 117 | <div>1.不向其他任何人泄露该账户信息(包括账户号码和代表账户的二维码),亦不将该注册账户借给他人使用,否则用户应承担由此产生的全部责任,并与实际使用人承担连带责任。</div> | ||
| 118 | <div>2.如您发现有他人冒用或盗用您的账户信息或任何其他未经合法授权之情形时,应立即以有效方式通知本公司,要求本公司暂停相关服务。同时,您理解本公司对您的请求采取行动需要合理时间,在此之前,本公司对已执行的指令及或所导致的您的损失不承担任何责任。</div> | ||
| 119 | <div>四、积分使用规则</div> | ||
| 120 | <div>为有效保障您使用本服务进行交易时的合法权益,您理解并同意接受以下规则:</div> | ||
| 121 | <div>1、就您使用本服务,本公司将通过多种方式向您授予积分,积分不具有现金价值,无论您通过何种方式获得积分,您都不得使用积分换取任何现金或货币。</div> | ||
| 122 | <div>2、积分不具备任何财产性质,并非您拥有所有权的财产,本公司有权单方面调整积分数值或调整本公司的积分规则,并在官方微信公众号“立乐家”公告积分规则变更事项。</div> | ||
| 123 | <div>3、您仅有权按本公司的积分规则,将所获积分兑换或换购本公司提供的指定的服务或产品。</div> | ||
| 124 | <div>4、如本公司怀疑您的积分的获得/使用存在欺诈、滥用或其它本公司认为不当的行为,本公司有权随时取消、限制或终止您的积分或积分使用。</div> | ||
| 125 | <div>5.积分累积规则:您仅在完成本公司指定的积分活动或任务时获得积分,超出本公司指定的范围,则不能获得积分。</div> | ||
| 126 | <div>6.积分使用规则:您仅在本公司的积分商城中使用积分兑换指定产品或服务,超出指定范围的,积分不能使用。</div> | ||
| 127 | <div>7.积分有效期:根据获得积分的活动或优惠时间制定,以会员中心规则为准。</div> | ||
| 128 | <div>8.在官方微信公众号出现系统故障等情况下,您将无法使用积分累计或兑换功能,您所获得的积分将在官方微信公众号系统恢复正常运作后的24小时内更新至您的会员账户。</div> | ||
| 129 | <div>五、“立乐家会员服务”使用限制</div> | ||
| 130 | <div>(一)您在使用立乐家会员服务时应遵守中华人民共和国相关法律法规、您所在国家或地区之法令及相关国际惯例,不以任何非法方式使用本服务或用于任何非法目的(包括但不限于用于禁止或限制交易物品的交易)。</div> | ||
| 131 | <div>(二)您不得利用立乐家会员身份从事侵害他人合法权益之行为,否则应承担所有相关法律责任,因此导致本公司或本公司雇员受损的,您应承担赔偿责任。上述行为包括但不限于:</div> | ||
| 132 | <div>1.侵害他人名誉权、隐私权、商业秘密、商标权、著作权、专利权等合法权益。</div> | ||
| 133 | <div>2.违反法定或约定之保密义务。</div> | ||
| 134 | <div>3.冒用他人名义使用本服务。</div> | ||
| 135 | <div>4.从事任何可能含有电脑病毒或是可能侵害本服务系统、资料之行为。</div> | ||
| 136 | <div>5.其他本公司有正当理由认为不适当之行为。</div> | ||
| 137 | <div>(三)您理解并同意,本公司不对因下述任一情况导致的任何损害赔偿承担责任,包括但不限于利润、商誉、使用、数据等方面的损失或其他损害赔偿 (无论本公司是否已被告知该等损害赔偿的可能性):</div> | ||
| 138 | <div>1.本公司有权判断,包含但不限于本公司认为您已经违反本章程的明文规定及精神,暂停、中止或终止向您提供本服务部分或全部功能,并移除您的资料及使用记录。</div> | ||
| 139 | <div>2. 本公司在发现异常交易行为或有疑义或有违法之虞时,有权不经通知先行暂停或终止该会员账户的使用,并拒绝您使用本服务之部分或全部功能。</div> | ||
| 140 | <div>3.在必要时,本公司无需事先通知即可终止提供本服务,并暂停、关闭或删除该账户及您账号中所有相关资料及档案,并将您在该立白会员账户内的积分和权益冻结或删除。</div> | ||
| 141 | <div>六、礼品卡</div> | ||
| 142 | <div>(一)礼品卡是指本公司发行的一种单用途商业预付卡,可用于用户之间赠送、兑换指定商品。</div> | ||
| 143 | <div>(二) 礼品卡为不记名卡,不挂失、不用于兑换或提取现金、不具有透支功能。</div> | ||
| 144 | <div>(三)在“立乐家”礼品卡小程序上购买的礼品卡,会员可通过相关页面登录自己的账户后,将该礼品卡绑定至会员账户。</div> | ||
| 145 | <div>(四)会员可在账户中同时绑定多张礼品卡,但最高不超过十张,同时可将购买的礼品卡转赠给其他用户,每张礼品卡仅可转赠一次。</div> | ||
| 146 | <div>(五)礼品卡的有效期以活动规则为准,逾期未进行兑换使用的礼品卡,购卡的金额将会在有效期结束后十五个工作日内退回购卡人的账户上。</div> | ||
| 147 | <div>(六)在礼品卡被绑定至会员帐户后,为了保护礼品卡使用的安全,您应保证不向他人泄露您的账户信息,否则一切后果自行承担。</div> | ||
| 148 | <div>(七)我司有权对礼品卡的使用范围、方式或条件等作出补充规定并通过活动规则、常见问题回答、信息推送等方式向购卡人/持卡人作出说明,购卡人及持卡人亦应遵守该等规定。</div> | ||
| 149 | <div>七、商品信息</div> | ||
| 150 | <div>本公司保留根据市场价格波动随时修改上线商品价格的权利而无须事先通知。在由于排版错误或价格信息错误的情况下以不正确的价格列出来的商品,本公司有拒绝或取消任何对以不正确的价格列出来的商品所下订单的权利。</div> | ||
| 151 | <div>八、订单</div> | ||
| 152 | <div>(一)在您下订单时,请您仔细确认所购商品的名称、数量、规格、尺寸、联系电话、地址、收货人等信息。收货人与用户本人不一致的,收货人的行为和意思表示视为用户的行为和意思表示,用户应对收货人的行为和意思表示承担连带责任。</div> | ||
| 153 | <div>(二)由于市场变化及各种以合理商业努力难以控制的因素的影响,本公司无法保证您提交的订单信息中希望购买的商品都会有货;如您拟购买的商品缺货,您有权取消订单。</div> | ||
| 154 | <div>(三)由于合理的或不可避免的送货延迟对您或第三方带来的任何损失,本公司不负任何责任。在这种情况下,本公司将尽快地把任何可预知的延迟情况通知您,并在此时请您选择是否取消订单。</div> | ||
| 155 | <div>九、系统中断或故障</div> | ||
| 156 | <div>系统因下列状况无法正常运作,导致您无法使用各项服务时,本公司不承担损害赔偿责任,包括但不限于:</div> | ||
| 157 | <div>(一)本公司在官方微信公众号“立乐家”上公告的系统停机维护期间。</div> | ||
| 158 | <div>(二)电信或网络设备出现故障不能进行数据传输的期间。</div> | ||
| 159 | <div>(三)因台风、地震、海啸、洪水、停电、战争、恐怖袭击等不可抗力之因素,造成本公司系统障碍不能执行业务的期间。</div> | ||
| 160 | <div>(四)由于黑客攻击、电信部门技术调整或故障、网站升级的问题等原因而造成的服务中断或者延迟的期间。</div> | ||
| 161 | <div>十、责任范围及责任限制</div> | ||
| 162 | <div>(一)本公司仅对本协议中列明的责任承担范围负责。</div> | ||
| 163 | <div>(二)立乐家会员用户信息是由用户本人自行提供的,用户本人应保证其信息之真实性、有效性、完整性和及时性,本公司对此不负任何责任。</div> | ||
| 164 | <div>(三)本服务之合作单位,所提供之服务品质及内容等由该合作单位自行负责。</div> | ||
| 165 | <div>(四)您经由本服务之使用下载或取得任何资料,应由您自行考量且自负风险,因资料之下载或取得而导致您电脑系统的任何损坏或资料流失,您应负完全责任。</div> | ||
| 166 | <div>(五)您自本公司及本公司工作人员或经由本服务取得之建议和资讯,无论其为书面或口头形式,均不构成本公司对本服务之保证。</div> | ||
| 167 | <div>(六)在法律允许的情况下,本公司对于与本协议有关或由本协议引起的任何间接的、惩罚性的、特殊的、派生的损失,不论是如何产生的,也不论是由对本协议的违反(包括违反保证)还是由侵权造成的,均不负有任何责任,无论事先是否已被告知此等损失的可能性。另外即使本协议规定的排他性救济没有达到其基本目的,也应排除本公司对上述损失的责任。</div> | ||
| 168 | <div>十一、商标、知识产权的保护</div> | ||
| 169 | <div>(一)本公司官方微信公众号“立乐家”上所有内容,包括但不限于著作、图片、档案、资讯、资料、网站架构、网站画面的安排、网页设计等,均由本公司或本公司关联企业依法拥有其知识产权,包括但不限于商标权、专利权、著作权、商业秘密等。</div> | ||
| 170 | <div>(二)非经本公司或本公司关联企业书面同意,任何单位或个人不得擅自使用、修改、复制、公开传播、改变、散布、发行或公开发表相关的程序或内容。</div> | ||
| 171 | <div>(三)尊重知识产权是您应尽的义务,如有违反上述条款, 本公司有权追究您的法律责任</div> | ||
| 172 | <div>十二、法律适用与管辖</div> | ||
| 173 | <div>本协议之效力、解释、变更、执行与争议解决均适用中华人民共和国法律,没有相关法律规定的,参照通用国际商业惯例和(或)行业惯例。因本协议产生之争议,双方应友好协商;协商不成,任何一方均可向协议签订地所在的人民法院提起诉讼。本协议签订地为广州市荔湾区陆居路二号。</div> | ||
| 174 | </div> | ||
| 175 | |||
| 176 | <div class="bottom-line"></div> | ||
| 177 | </div> | ||
| 178 | </div> | ||
| 179 | |||
| 180 | <!-- 隐私协议--> | ||
| 181 | <div class="model rule-model" v-if="data.index == 'privacy'"> | ||
| 182 | <div class="model-close" @click="modelCloseHandler"></div> | ||
| 183 | <div class="model-content"> | ||
| 184 | <div class="model-head-line"></div> | ||
| 185 | <div class="model-title">隐私政策</div> | ||
| 186 | <div class="text-container"> | ||
| 187 | <div>立乐家(以下简称“我们”)非常重视用户的隐私和个人信息保护。您在购买我们的产品与/或使用我们的服务时,我们可能会收集和使用您的相关信息。我们希望通过《隐私政策》(“本隐私政策”)向您说明我们在您购买我们的产品与/或使用我们的服务时如何收集、使用、保存、共享和转让这些信息,以及我们为您提供的访问、更新、删除和保护这些信息的方式。</div> | ||
| 188 | <div>本隐私政策与您所使用的立乐家服务以及该服务所包括的各种业务功能(以下统称“我们的产品与/或服务”)息息相关,希望您在购买我们的产品与/或使用我们的服务前仔细阅读并确认您已经充分理解本政策所写明的内容,并让您可以按照本隐私政策的指引做出您认为适当的选择。如果您购买我们的产品与/或使用我们的服务,即意味着您同意本隐私政策内容,并且同意我们按照本隐私政策收集、使用、保存和共享您的相关信息。</div> | ||
| 189 | <div>一、 我们如何收集您的信息</div> | ||
| 190 | <div>我们会出于本政策所述的以下目的,收集和使用您的个人信息:</div> | ||
| 191 | <div>1.用户注册</div> | ||
| 192 | <div>您首先需要注册一个立白立乐家账户成为我们的用户。当您注册时,您需要至少向我们提供您准备使用的立白立乐家账户名、密码、您本人的手机号码,我们将通过发送短信验证码的方式来验证您的身份是否有效。您的账户名为您的默认昵称,您可以修改补充您的昵称、性别、生日、以及您的实名验证相关信息,这些信息均属于您的“账户信息”。您补充的账户信息将有助于我们为您提供个性化的商品推荐和更优的购物体验,但如果您不提供这些补充信息,不会影响您网上购物的基本功能。</div> | ||
| 193 | <div>2.展示和推送商品或服务</div> | ||
| 194 | <div>为改善我们的产品或服务、向您提供个性化的信息搜索及交易服务,我们会根据您的浏览及搜索记录、设备信息、位置信息、订单信息,提取您的浏览、搜索偏好、行为习惯、位置信息等特征,基于特征标签进行展示、推送信息。</div> | ||
| 195 | <div>3.提供商品或服务</div> | ||
| 196 | <div>为便于向您交付商品或服务,您需提供收货人姓名、收货地址、邮政编码、收货人联系电话。如果我们委托第三方向您交付时,我们会在征得您同意后将上述信息共享给第三方。如果您拒绝提供此类信息,我们将无法完成相关交付服务。</div> | ||
| 197 | <div>4.提供安全保障</div> | ||
| 198 | <div>为提高您使用我们的产品与/或服务时系统的安全性,更准确地预防钓鱼网站欺诈和保护账户安全,我们可能会通过了解您的浏览信息、订单信息、您常用的软件信息、设备信息等手段来判断您的账号风险,并可能会记录一些我们认为有风险的链接(“URL”);我们也会收集您的设备信息对于立白立乐家系统问题进行分析、统计流量并排查可能存在的风险、在您选择向我们发送异常信息时予以排查。</div> | ||
| 199 | <div>二、 我们如何使用Cookie</div> | ||
| 200 | <div>1.为实现您联机体验的个性化需求,使您获得更轻松的访问体验。我们会在您的移动设备上发送一个或多个名为Cookies的小数据文件,指定给您的Cookies是唯一的,它只能被将Cookies发布给您的域中的Web服务器读取。我们向您发送Cookies是为了简化您重复登录的步骤、存储您的购物偏好或您购物车中的商品等数据进而为您提供购物的偏好设置、帮助您优化对广告的选择与互动、帮助判断您的登录状态以及账户或数据安全;</div> | ||
| 201 | <div>2.我们不会将Cookies用于本隐私政策所述目的之外的任何用途。您可根据自己的偏好管理或删除Cookies。您可以清除设备上保存的所有Cookies,大部分网络浏览器都设有阻止Cookies的功能。但如果您这么做,您可能需要在每一次访问我们网站时亲自更改用户设置,而且您之前所记录的相应信息也均会被删除,并且可能会对您所使用服务的安全性有一定影响。</div> | ||
| 202 | <div>三、我们如何共享、转让、公开、披露您的个人信息</div> | ||
| 203 | <div>(一)共享</div> | ||
| 204 | <div>我们不会与立乐家以外的任何公司、组织和个人共享您的个人信息,但以下情况除外:</div> | ||
| 205 | <div>1.事先获得您明确的同意或授权;</div> | ||
| 206 | <div>2.根据适用的法律法规、法律程序的要求、强制性的行政或司法要求所必须的情况下进行提供;</div> | ||
| 207 | <div>3.我们可能会将您的个人信息与我们的关联方共享。但我们只会共享必要的个人信息,且受本隐私政策中所声明目的的约束。我们的关联方如要改变个人信息的处理目的,将再次征求您的授权同意;</div> | ||
| 208 | <div>4.我们可能会向合作伙伴等第三方共享您的订单信息、账户信息、设备信息以及位置信息,以保障为您提供的服务顺利完成。但我们仅会出于合法、正当、必要、特定、明确的目的共享您的个人信息,并且只会共享提供服务所必要的个人信息。我们的合作伙伴无权将共享的个人信息用于任何其他用途;</div> | ||
| 209 | <div>5.对我们与之共享个人信息的公司、组织和个人,我们会与其签署严格的保密协定,要求他们按照我们的说明、本隐私政策以及其他任何相关的保密和安全措施来处理个人信息。</div> | ||
| 210 | <div>(二)转让</div> | ||
| 211 | <div>我们不会将您的个人信息转让给任何公司、组织和个人,但以下情况除外:</div> | ||
| 212 | <div>1.事先获得您明确的同意或授权;</div> | ||
| 213 | <div>2.根据适用的法律法规、法律程序的要求、强制性的行政或司法要求所必须的情况进行提供;</div> | ||
| 214 | <div>3.在涉及合并、收购、资产转让或类似的交易时,如涉及到个人信息转让,我们会要求新的持有您个人信息的公司、组织继续受本隐私政策的约束,否则,我们将要求该公司、组织重新向您征求授权同意。</div> | ||
| 215 | <div>(三)公开披露</div> | ||
| 216 | <div>我们仅会在以下情况下,才会公开披露您的个人信息:</div> | ||
| 217 | <div>1.根据您的需求,在您明确同意的披露方式下披露您所指定的个人信息;</div> | ||
| 218 | <div>2.根据法律、法规的要求、强制性的行政执法或司法要求所必须提供您个人信息的情况下,我们可能会依据所要求的个人信息类型和披露方式公开披露您的个人信息。</div> | ||
| 219 | <div>(四)共享、转让、公开披露个人信息时事先征得授权同意的例外</div> | ||
| 220 | <div>以下情形中,共享、转让、公开披露您的个人信息无需事先征得您的授权同意:</div> | ||
| 221 | <div>1.与国家安全、国防安全有关的;</div> | ||
| 222 | <div>2.与公共安全、公共卫生、重大公共利益有关的;</div> | ||
| 223 | <div>3.与犯罪侦查、起诉、审判和判决执行等有关的;</div> | ||
| 224 | <div>4.出于维护您或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;</div> | ||
| 225 | <div>5.您自行向社会公众公开的个人信息;</div> | ||
| 226 | <div>6.从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道。</div> | ||
| 227 | <div>根据法律规定,共享、转让经去标识化处理的个人信息,且确保数据接收方无法复原并重新识别个人信息主体的,不属于个人信息的对外共享、转让及公开披露行为,对此类数据的保存及处理将无需另行向您通知并征得您的同意。</div> | ||
| 228 | <div>四、我们如何保护您的个人信息安全</div> | ||
| 229 | <div>1.我们已采取符合业界标准、合理可行的安全防护措施保护您提供的个人信息安全,防止个人信息遭到未经授权访问、公开披露、使用、修改、损坏或丢失;</div> | ||
| 230 | <div>2.我们会采取合理可行的措施,尽力避免收集无关的个人信息。我们只会在账户有效期内保留您的个人信息,除非法律相关规定或司法行政要求延长保留期;</div> | ||
| 231 | <div>3.我们仅允许有必要知晓这些信息的立白立乐家及立白立乐家关联方的员工、合作伙伴访问个人信息,并为此设置了严格的访问权限控制和监控机制。我们同时要求可能接触到您个人信息的所有人员履行相应的保密义务;</div> | ||
| 232 | <div>4.互联网并非绝对安全的环境,而且电子邮件、即时通讯、社交软件等与其他用户的交流方式无法确定是否完全加密,我们建议您使用此类工具时请使用复杂密码,并注意保护您的个人信息安全;</div> | ||
| 233 | <div>5.在不幸发生个人信息安全事件后,我们将按照法律法规的要求向您告知:安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施等。事件相关情况我们将以邮件、信函、电话、推送通知等方式告知您,难以逐一告知个人信息主体时,我们会采取合理、有效的方式发布公告。</div> | ||
| 234 | <div>五、您如何管理您的个人信息</div> | ||
| 235 | <div>您可以通过以下方式访问及管理您的个人信息:</div> | ||
| 236 | <div>(一)访问您的个人信息</div> | ||
| 237 | <div>您有权访问您的个人信息,法律法规规定的例外情况除外。您可以通过以下方式自行访问您的个人信息:</div> | ||
| 238 | <div>(1)账户信息——如果您希望访问或编辑您的账户中的个人基本资料信息和支付信息、更改您的密码、添加安全信息或关闭您的账户等,您可以通过登录账号通过“账号管理”执行此类操作。</div> | ||
| 239 | <div>(2)订单信息:您可以在订单中心查阅或清除您的订单记录、交易记录等。</div> | ||
| 240 | <div>如果您无法通过上述路径访问该等个人信息,您可以随时通过客服与我们取得联系。我们将在15天内回复您的访问请求。</div> | ||
| 241 | <div>对于您在使用我们的产品或服务过程中产生的其他个人信息,我们将根据本条“(四)响应您的上述请求”中的相关安排向您提供。</div> | ||
| 242 | <div>(二)更正或补充您的个人信息</div> | ||
| 243 | <div>当您发现我们处理的关于您的个人信息有错误时,您有权要求我们做出更正或补充。您可以通过“(一)访问您的个人信息”中列明的方式提出更正或补充申请。</div> | ||
| 244 | <div>(三)删除您的个人信息</div> | ||
| 245 | <div>您可以通过“(一)访问您的个人信息”中列明的方式删除您的部分个人信息。</div> | ||
| 246 | <div>在以下情形中,您可以向我们提出删除个人信息的请求:</div> | ||
| 247 | <div>1.如果我们处理个人信息的行为违反法律法规;</div> | ||
| 248 | <div>2.如果我们收集、使用您的个人信息,却未征得您的明确同意</div> | ||
| 249 | <div>3.如果我们处理个人信息的行为严重违反了与您的约定;</div> | ||
| 250 | <div>4.如果您不再使用我们的产品或服务,或您主动注销了账号;</div> | ||
| 251 | <div>5.如果我们永久不再为您提供产品或服务。</div> | ||
| 252 | <div>若我们决定响应您的删除请求,我们还将同时尽可能通知从我们处获得您的个人信息的主体,要求其及时删除,除非法律法规另有规定,或这些主体获得您的独立授权。</div> | ||
| 253 | <div>当您从我们的服务中删除信息后,我们可能不会立即从备份系统中删除相应的信息,但会在备份更新时删除这些信息。</div> | ||
| 254 | <div>(四)响应您的上述请求</div> | ||
| 255 | <div>为保障安全,您可能需要提供书面请求,或以其他方式证明您的身份。我们可能会先要求您验证自己的身份,然后再处理您的请求。</div> | ||
| 256 | <div>我们将在15天内做出答复。如您不满意,还可以通过客服发起投诉。</div> | ||
| 257 | <div>对于您合理的请求,我们原则上不收取费用,但对多次重复、超出合理限度的请求,我们将视情收取一定成本费用。对于那些无端重复、需要过多技术手段(例如,需要开发新系统或从根本上改变现行惯例)、给他人合法权益带来风险或者非常不切实际的请求,我们可能会予以拒绝。</div> | ||
| 258 | <div>在以下情形中,按照法律法规要求,我们将无法响应您的请求:</div> | ||
| 259 | <div>1.与国家安全、国防安全有关的;</div> | ||
| 260 | <div>2.与公共安全、公共卫生、重大公共利益有关的;</div> | ||
| 261 | <div>3.与犯罪侦查、起诉、审判和执行判决等有关的;</div> | ||
| 262 | <div>4.有充分证据表明个人信息主体存在主观恶意或滥用权利的;</div> | ||
| 263 | <div>5.响应您的请求将导致您或其他个人、组织的合法权益受到严重损害的;</div> | ||
| 264 | <div>6.涉及商业秘密的。</div> | ||
| 265 | <div>六、未成年人的个人信息保护</div> | ||
| 266 | <div>1.立乐家非常重视对未成年人个人信息的保护。若您是18周岁以下的未成年人,在使用我们的产品与/或服务前,建议您请您的父母或监护人仔细阅读本隐私权政策,并在征得您的父母或监护人同意的前提下使用我们的产品与/或服务及向我们提供信息;</div> | ||
| 267 | <div>2.对于经父母或法定监护人同意而收集未成年人个人信息的情况,我们只会在受到法律允许、父母或监护人明确同意或者保护未成年人所必要的情况下使用或公开披露此信息;</div> | ||
| 268 | <div>3.如果我们发现自己在未事先获得可证实的父母或法定监护人同意的情况下收集了未成年人的个人信息,则会设法尽快删除相关数据。</div> | ||
| 269 | <div>七、通知和修订</div> | ||
| 270 | <div>为给您提供更好的服务以及随着立白立乐家业务的发展,本隐私政策也会随之更新。但未经您明确同意,我们不会削减您依据本隐私政策所应享有的权利。我们会通过在立白立乐家上发出更新版本并在生效前通过网站公告或以其他适当方式提醒您相关内容的更新,也请您访问立白立乐家以便及时了解最新的隐私政策。</div> | ||
| 271 | <div>八、如何联系我们</div> | ||
| 272 | <div>您可以通过以下方式与我们联系,我们将在15天内回复您的请求:</div> | ||
| 273 | <div>1.如对本政策内容有任何疑问、意见或建议,您可通过客服与我们联系。客服电话:020-81808822</div> | ||
| 274 | <div>2.如发现个人信息可能被泄露,您可以通过客服提起投诉举报。客服电话:020-81808822</div> | ||
| 275 | </div> | ||
| 276 | <div class="bottom-line"></div> | ||
| 277 | </div> | ||
| 278 | </div> | ||
| 279 | |||
| 84 | <!-- 奖品--> | 280 | <!-- 奖品--> |
| 85 | <div class="model rule-model" v-if="data.index == 'prize'"> | 281 | <div class="model rule-model" v-if="data.index == 'prize'"> |
| 86 | <div class="model-close" @click="modelCloseHandler"></div> | 282 | <div class="model-close" @click="modelCloseHandler"></div> |
| ... | @@ -204,6 +400,7 @@ export default { | ... | @@ -204,6 +400,7 @@ export default { |
| 204 | } | 400 | } |
| 205 | 401 | ||
| 206 | .model-title { | 402 | .model-title { |
| 403 | text-align: center; | ||
| 207 | font-size: 45px; | 404 | font-size: 45px; |
| 208 | font-weight: bold; | 405 | font-weight: bold; |
| 209 | } | 406 | } |
| ... | @@ -274,10 +471,30 @@ export default { | ... | @@ -274,10 +471,30 @@ export default { |
| 274 | .sm-width { | 471 | .sm-width { |
| 275 | width: 480px !important; | 472 | width: 480px !important; |
| 276 | margin-bottom: 30px; | 473 | margin-bottom: 30px; |
| 277 | 474 | ||
| 278 | div { | 475 | div { |
| 279 | font-weight: 600; | 476 | font-weight: 600; |
| 280 | } | 477 | } |
| 281 | } | 478 | } |
| 282 | } | 479 | } |
| 480 | |||
| 481 | .text-container { | ||
| 482 | overflow: scroll; | ||
| 483 | max-height: 700px; | ||
| 484 | |||
| 485 | div { | ||
| 486 | font-weight: 600; | ||
| 487 | width: 90%; | ||
| 488 | margin: auto; | ||
| 489 | margin-top: 15px; | ||
| 490 | text-indent: 52px; | ||
| 491 | text-align: left; | ||
| 492 | color: #323232; | ||
| 493 | font-size: 26px; | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | .bottom-line{ | ||
| 498 | height: 30px; | ||
| 499 | } | ||
| 283 | </style> | 500 | </style> | ... | ... |
| ... | @@ -15,12 +15,17 @@ | ... | @@ -15,12 +15,17 @@ |
| 15 | class="prize-thumb" | 15 | class="prize-thumb" |
| 16 | v-bind:style="{backgroundImage:'url(' + data.drawResult.thumb + ')'}" | 16 | v-bind:style="{backgroundImage:'url(' + data.drawResult.thumb + ')'}" |
| 17 | ></div> | 17 | ></div> |
| 18 | |||
| 18 | <div class="prize-name">{{data.drawResult.prizeName}}</div> | 19 | <div class="prize-name">{{data.drawResult.prizeName}}</div> |
| 20 | <div | ||
| 21 | v-if="data.drawResult.prizeType == 'coupon'" | ||
| 22 | class="prize-sn" | ||
| 23 | >{{data.drawResult.prizeSn}}</div> | ||
| 19 | <div class="tip-container"> | 24 | <div class="tip-container"> |
| 20 | <span class="use-tip">奖品说明</span> | 25 | <span class="use-tip">奖品说明</span> |
| 21 | </div> | 26 | </div> |
| 22 | <div class="tip-container" v-if="data.drawResult.prizeType == 'integral'"> | 27 | <div class="tip-container" v-if="data.drawResult.prizeType == 'integral'"> |
| 23 | <span class="tip">积分可以在立乐家商城兑换礼品</span> | 28 | <span class="tip">积分可以在立乐家积分商场兑换礼品</span> |
| 24 | </div> | 29 | </div> |
| 25 | <div class="tip-container" v-if="data.drawResult.prizeType == 'coupon'"> | 30 | <div class="tip-container" v-if="data.drawResult.prizeType == 'coupon'"> |
| 26 | <span class="tip">优惠券可以在立乐家商城购物当现金使用</span> | 31 | <span class="tip">优惠券可以在立乐家商城购物当现金使用</span> |
| ... | @@ -113,17 +118,18 @@ export default { | ... | @@ -113,17 +118,18 @@ export default { |
| 113 | return { | 118 | return { |
| 114 | loading: false, | 119 | loading: false, |
| 115 | data: this.value, | 120 | data: this.value, |
| 116 | submitForm: !this.value || !this.value.drawResult | 121 | submitForm: |
| 117 | ? { | 122 | !this.value || !this.value.drawResult |
| 118 | drawCode: "", | 123 | ? { |
| 119 | contactName: "", | 124 | drawCode: "", |
| 120 | contactMobile: "", | 125 | contactName: "", |
| 121 | province: "", | 126 | contactMobile: "", |
| 122 | city: "", | 127 | province: "", |
| 123 | district: "", | 128 | city: "", |
| 124 | address: "" | 129 | district: "", |
| 125 | } | 130 | address: "" |
| 126 | : this.value.drawResult | 131 | } |
| 132 | : this.value.drawResult | ||
| 127 | }; | 133 | }; |
| 128 | }, | 134 | }, |
| 129 | methods: { | 135 | methods: { |
| ... | @@ -355,4 +361,10 @@ input::-webkit-input-placeholder { | ... | @@ -355,4 +361,10 @@ input::-webkit-input-placeholder { |
| 355 | color: #4f9984; | 361 | color: #4f9984; |
| 356 | font-size: 26px; | 362 | font-size: 26px; |
| 357 | } | 363 | } |
| 364 | |||
| 365 | .prize-sn { | ||
| 366 | text-align: center; | ||
| 367 | font-size: 30px; | ||
| 368 | font-weight: 600; | ||
| 369 | } | ||
| 358 | </style> | 370 | </style> | ... | ... |
| ... | @@ -79,7 +79,7 @@ export default { | ... | @@ -79,7 +79,7 @@ export default { |
| 79 | toWorksViewHandler(code) { | 79 | toWorksViewHandler(code) { |
| 80 | let link = location.origin + location.pathname; | 80 | let link = location.origin + location.pathname; |
| 81 | link += "?worksCode=" + code; | 81 | link += "?worksCode=" + code; |
| 82 | as.setShare(link, null, null, null); | 82 | as.setShare(link, "", "", ""); |
| 83 | this.$emit("worksDetail", { worksCode: code }); | 83 | this.$emit("worksDetail", { worksCode: code }); |
| 84 | }, | 84 | }, |
| 85 | searchWorksHandler(action) { | 85 | searchWorksHandler(action) { |
| ... | @@ -109,6 +109,7 @@ export default { | ... | @@ -109,6 +109,7 @@ export default { |
| 109 | tempList = []; | 109 | tempList = []; |
| 110 | list.push(tempList); | 110 | list.push(tempList); |
| 111 | } | 111 | } |
| 112 | this._changeImageList(res.list[index]); | ||
| 112 | tempList.push(res.list[index]); | 113 | tempList.push(res.list[index]); |
| 113 | } | 114 | } |
| 114 | // console.log(list); | 115 | // console.log(list); |
| ... | @@ -124,8 +125,28 @@ export default { | ... | @@ -124,8 +125,28 @@ export default { |
| 124 | Toast.clear(true); | 125 | Toast.clear(true); |
| 125 | }); | 126 | }); |
| 126 | }, | 127 | }, |
| 128 | _changeImageList(works) { | ||
| 129 | let worksList = works.worksList; | ||
| 130 | if (!worksList || worksList.length == 0) { | ||
| 131 | return; | ||
| 132 | } | ||
| 133 | if (worksList[0].worksType == "pic") { | ||
| 134 | return; | ||
| 135 | } | ||
| 136 | let changeIndex = -1; | ||
| 137 | for (let index = 0; index < worksList.length; index++) { | ||
| 138 | if (worksList[index].worksType == "pic") { | ||
| 139 | changeIndex = index; | ||
| 140 | break; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | if (changeIndex > -1) { | ||
| 144 | let worksTmp = worksList.splice(changeIndex, 1); | ||
| 145 | worksList.unshift(worksTmp[0]); | ||
| 146 | works.worksList = worksList; | ||
| 147 | } | ||
| 148 | }, | ||
| 127 | refreshMore() { | 149 | refreshMore() { |
| 128 | // console.log("refresh more"); | ||
| 129 | this.listForm.page++; | 150 | this.listForm.page++; |
| 130 | this.searchWorksHandler(); | 151 | this.searchWorksHandler(); |
| 131 | } | 152 | } | ... | ... |
| ... | @@ -8,9 +8,16 @@ | ... | @@ -8,9 +8,16 @@ |
| 8 | <div class="head-line"></div> | 8 | <div class="head-line"></div> |
| 9 | <div class="swipe"> | 9 | <div class="swipe"> |
| 10 | <van-swipe :autoplay="5000"> | 10 | <van-swipe :autoplay="5000"> |
| 11 | <van-swipe-item v-for="(works, index) in formData.worksList" :key="index"> | 11 | <van-swipe-item v-for="(item, index) in formData.worksList" :key="index"> |
| 12 | <!-- <img :src="works.worksUrl" /> --> | 12 | <!-- <img :src="works.worksUrl" /> --> |
| 13 | <div class="img" v-bind:style="{backgroundImage:'url(' + works.worksUrl + ')'}"></div> | 13 | <div |
| 14 | v-if="item.worksType=='pic'" | ||
| 15 | class="img" | ||
| 16 | v-bind:style="{backgroundImage:'url(' + item.worksUrl + ')'}" | ||
| 17 | ></div> | ||
| 18 | <video v-if="item.worksType=='video'" controls> | ||
| 19 | <source :src="item.worksUrl" type="video/mp4" /> | ||
| 20 | </video> | ||
| 14 | </van-swipe-item> | 21 | </van-swipe-item> |
| 15 | </van-swipe> | 22 | </van-swipe> |
| 16 | </div> | 23 | </div> |
| ... | @@ -43,7 +50,6 @@ | ... | @@ -43,7 +50,6 @@ |
| 43 | <div class="msg">{{formData.slogan}}</div> | 50 | <div class="msg">{{formData.slogan}}</div> |
| 44 | </div> | 51 | </div> |
| 45 | 52 | ||
| 46 | |||
| 47 | <div class="text-container space top"> | 53 | <div class="text-container space top"> |
| 48 | <div class="label">个人简介:</div> | 54 | <div class="label">个人简介:</div> |
| 49 | <div class="msg">{{formData.profile}}</div> | 55 | <div class="msg">{{formData.profile}}</div> |
| ... | @@ -165,6 +171,11 @@ export default { | ... | @@ -165,6 +171,11 @@ export default { |
| 165 | width: 630px; | 171 | width: 630px; |
| 166 | background-size: cover; | 172 | background-size: cover; |
| 167 | } | 173 | } |
| 174 | |||
| 175 | video { | ||
| 176 | height: 451px; | ||
| 177 | width: 630px; | ||
| 178 | } | ||
| 168 | } | 179 | } |
| 169 | 180 | ||
| 170 | .space { | 181 | .space { | ... | ... |
| ... | @@ -11,8 +11,15 @@ | ... | @@ -11,8 +11,15 @@ |
| 11 | <div class="self-content"> | 11 | <div class="self-content"> |
| 12 | <div class="swipe"> | 12 | <div class="swipe"> |
| 13 | <van-swipe :autoplay="5000"> | 13 | <van-swipe :autoplay="5000"> |
| 14 | <van-swipe-item v-for="(works, index) in formData.worksList" :key="index"> | 14 | <van-swipe-item v-for="(item, index) in formData.worksList" :key="index"> |
| 15 | <div class="img" v-bind:style="{backgroundImage:'url(' + works.worksUrl + ')'}"></div> | 15 | <div |
| 16 | v-if="item.worksType=='pic'" | ||
| 17 | class="img" | ||
| 18 | v-bind:style="{backgroundImage:'url(' + item.worksUrl + ')'}" | ||
| 19 | ></div> | ||
| 20 | <video v-if="item.worksType=='video'" controls> | ||
| 21 | <source :src="item.worksUrl" type="video/mp4" /> | ||
| 22 | </video> | ||
| 16 | </van-swipe-item> | 23 | </van-swipe-item> |
| 17 | </van-swipe> | 24 | </van-swipe> |
| 18 | </div> | 25 | </div> |
| ... | @@ -213,6 +220,11 @@ export default { | ... | @@ -213,6 +220,11 @@ export default { |
| 213 | width: 265px; | 220 | width: 265px; |
| 214 | background-size: cover; | 221 | background-size: cover; |
| 215 | } | 222 | } |
| 223 | |||
| 224 | video { | ||
| 225 | height: 190px; | ||
| 226 | width: 265px; | ||
| 227 | } | ||
| 216 | } | 228 | } |
| 217 | 229 | ||
| 218 | .space { | 230 | .space { | ... | ... |
| ... | @@ -116,21 +116,20 @@ export default { | ... | @@ -116,21 +116,20 @@ export default { |
| 116 | } | 116 | } |
| 117 | }, | 117 | }, |
| 118 | initActivity() { | 118 | initActivity() { |
| 119 | this.init = true; | 119 | Toast.loading({ |
| 120 | // Toast.loading({ | 120 | mask: true, |
| 121 | // mask: true, | 121 | message: "加载中..." |
| 122 | // message: "加载中..." | 122 | }); |
| 123 | // }); | 123 | httpGet({ url: urls.myWork }).then(res => { |
| 124 | // httpGet({ url: urls.myWork }).then(res => { | 124 | this.init = true; |
| 125 | // this.init = true; | 125 | this.formData = res.data || {}; |
| 126 | // this.formData = res.data || {}; | 126 | if (!res.data) { |
| 127 | // if (!res.data) { | 127 | this.formEdit = true; |
| 128 | // this.formEdit = true; | 128 | } else { |
| 129 | // } else { | 129 | this.formEdit = false; |
| 130 | // this.formEdit = false; | 130 | } |
| 131 | // } | 131 | Toast.clear(); |
| 132 | // Toast.clear(); | 132 | }); |
| 133 | // }); | ||
| 134 | }, | 133 | }, |
| 135 | showRuleHandler() { | 134 | showRuleHandler() { |
| 136 | this.model.show = true; | 135 | this.model.show = true; |
| ... | @@ -176,7 +175,7 @@ export default { | ... | @@ -176,7 +175,7 @@ export default { |
| 176 | }, | 175 | }, |
| 177 | created() { | 176 | created() { |
| 178 | this.initUrlQuery(); | 177 | this.initUrlQuery(); |
| 179 | // this.initActivity(); | 178 | this.initActivity(); |
| 180 | }, | 179 | }, |
| 181 | components: { | 180 | components: { |
| 182 | BottomTool, | 181 | BottomTool, | ... | ... |
| ... | @@ -63,7 +63,7 @@ | ... | @@ -63,7 +63,7 @@ |
| 63 | <div class="sys-btn-02" :class="{disabled : !autoRegister}" @click="submitFormHandler">确认提交</div> | 63 | <div class="sys-btn-02" :class="{disabled : !autoRegister}" @click="submitFormHandler">确认提交</div> |
| 64 | 64 | ||
| 65 | <div | 65 | <div |
| 66 | class="center base-margin auto-register-tips" | 66 | class="center base-margin-top auto-register-tips" |
| 67 | @click="acceptRegisterHandler" | 67 | @click="acceptRegisterHandler" |
| 68 | v-if="formData.worksCode == '' || formData.worksCode == null " | 68 | v-if="formData.worksCode == '' || formData.worksCode == null " |
| 69 | > | 69 | > |
| ... | @@ -71,6 +71,15 @@ | ... | @@ -71,6 +71,15 @@ |
| 71 | <div class="tips">自动注册为立白集团会员,立享会员权益,详见“更多福利”</div> | 71 | <div class="tips">自动注册为立白集团会员,立享会员权益,详见“更多福利”</div> |
| 72 | </div> | 72 | </div> |
| 73 | 73 | ||
| 74 | <div class="center base-margin auto-register-tips"> | ||
| 75 | <div class="icon-register" :class="{activity : privacy}"></div> | ||
| 76 | <div class="tips"> | ||
| 77 | 我已阅读并同意 | ||
| 78 | <u @click="showAgreementHandler">用户协议</u>和 | ||
| 79 | <u @click="showPrivacyHandler">隐私政策</u> | ||
| 80 | </div> | ||
| 81 | </div> | ||
| 82 | |||
| 74 | <van-popup position="bottom" :style="{ height: '40%' }" v-model="area.show"> | 83 | <van-popup position="bottom" :style="{ height: '40%' }" v-model="area.show"> |
| 75 | <van-area | 84 | <van-area |
| 76 | :area-list="areaList" | 85 | :area-list="areaList" |
| ... | @@ -108,6 +117,7 @@ export default { | ... | @@ -108,6 +117,7 @@ export default { |
| 108 | data() { | 117 | data() { |
| 109 | return { | 118 | return { |
| 110 | autoRegister: true, | 119 | autoRegister: true, |
| 120 | privacy: true, | ||
| 111 | successModelVisiable: true, | 121 | successModelVisiable: true, |
| 112 | area: { | 122 | area: { |
| 113 | show: false | 123 | show: false |
| ... | @@ -140,6 +150,12 @@ export default { | ... | @@ -140,6 +150,12 @@ export default { |
| 140 | if (!this.autoRegister) { | 150 | if (!this.autoRegister) { |
| 141 | } | 151 | } |
| 142 | }, | 152 | }, |
| 153 | showAgreementHandler() { | ||
| 154 | this.$emit("agreement"); | ||
| 155 | }, | ||
| 156 | showPrivacyHandler() { | ||
| 157 | this.$emit("privacy"); | ||
| 158 | }, | ||
| 143 | submitFormHandler() { | 159 | submitFormHandler() { |
| 144 | if (!this.autoRegister) { | 160 | if (!this.autoRegister) { |
| 145 | return; | 161 | return; |
| ... | @@ -197,9 +213,12 @@ export default { | ... | @@ -197,9 +213,12 @@ export default { |
| 197 | .then(res => { | 213 | .then(res => { |
| 198 | this.loading = false; | 214 | this.loading = false; |
| 199 | Toast.clear(); | 215 | Toast.clear(); |
| 216 | let data = { | ||
| 217 | isFirst : !this.formData.worksCode ? 1 : 0, | ||
| 218 | worksCode : res | ||
| 219 | }; | ||
| 200 | this.formData.worksCode = res; | 220 | this.formData.worksCode = res; |
| 201 | console.log("submit === =", res); | 221 | this.$emit("submit", data); |
| 202 | this.$emit("submit", res); | ||
| 203 | }) | 222 | }) |
| 204 | .catch(res => { | 223 | .catch(res => { |
| 205 | this.loading = false; | 224 | this.loading = false; |
| ... | @@ -360,8 +379,12 @@ export default { | ... | @@ -360,8 +379,12 @@ export default { |
| 360 | background-size: 100%; | 379 | background-size: 100%; |
| 361 | } | 380 | } |
| 362 | 381 | ||
| 363 | .base-margin { | 382 | .base-margin-top{ |
| 364 | margin-top: 40px; | 383 | margin-top: 40px; |
| 384 | } | ||
| 385 | |||
| 386 | .base-margin { | ||
| 387 | margin-top: 20px; | ||
| 365 | margin-bottom: 80px; | 388 | margin-bottom: 80px; |
| 366 | } | 389 | } |
| 367 | 390 | ... | ... |
src/pages/sign/components/ImageClipper.vue
0 → 100755
| 1 | <template> | ||
| 2 | <div class="clipper-container" ref="clipper"> | ||
| 3 | <div class="full-mask" @click="_cancel"></div> | ||
| 4 | <canvas ref="canvas"></canvas> | ||
| 5 | |||
| 6 | <!-- 裁剪部分 --> | ||
| 7 | <div class="clipper-part"> | ||
| 8 | <div class="pCanvas-container"> | ||
| 9 | <canvas ref="pCanvas"></canvas> | ||
| 10 | </div> | ||
| 11 | </div> | ||
| 12 | |||
| 13 | <!-- 底部操作栏 --> | ||
| 14 | <div class="action-bar"> | ||
| 15 | <div class="button" @click="_clipper">确认</div> | ||
| 16 | </div> | ||
| 17 | |||
| 18 | <!-- 背景遮罩 --> | ||
| 19 | <div class="mask" :class="{opacity: maskShow}"></div> | ||
| 20 | |||
| 21 | <!-- 手势操作层 --> | ||
| 22 | <div class="gesture-mask" ref="gesture"></div> | ||
| 23 | </div> | ||
| 24 | </template> | ||
| 25 | |||
| 26 | <style lang="less"> | ||
| 27 | .position() { | ||
| 28 | position: absolute; | ||
| 29 | top: 0; | ||
| 30 | bottom: 0; | ||
| 31 | left: 0; | ||
| 32 | right: 0; | ||
| 33 | z-index: 2000; | ||
| 34 | } | ||
| 35 | |||
| 36 | .full-mask { | ||
| 37 | background-color: #fff; | ||
| 38 | opacity: 0.8; | ||
| 39 | position: fixed; | ||
| 40 | width: 100%; | ||
| 41 | height: 100%; | ||
| 42 | top: 0; | ||
| 43 | bottom: 0; | ||
| 44 | left: 0; | ||
| 45 | right: 0; | ||
| 46 | z-index: 1000; | ||
| 47 | } | ||
| 48 | |||
| 49 | .clipper-container { | ||
| 50 | .position(); | ||
| 51 | line-height: 0; | ||
| 52 | background-color: #000; | ||
| 53 | .clipper-part { | ||
| 54 | .position(); | ||
| 55 | bottom: 61px; | ||
| 56 | z-index: 2102; | ||
| 57 | .pCanvas-container { | ||
| 58 | position: absolute; | ||
| 59 | top: 50%; | ||
| 60 | left: 50%; | ||
| 61 | transform: translate(-50%, -50%); | ||
| 62 | border: 2px solid #fff; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | .action-bar { | ||
| 66 | box-sizing: content-box; | ||
| 67 | .position(); | ||
| 68 | top: auto; | ||
| 69 | z-index: 2103; | ||
| 70 | height: 80px; | ||
| 71 | line-height: 80px; | ||
| 72 | border-top: 1px solid rgba(256, 256, 256, 0.3); | ||
| 73 | .button { | ||
| 74 | line-height: 80px; | ||
| 75 | height: 80px; | ||
| 76 | font-size: 26px; | ||
| 77 | color: #fff; | ||
| 78 | background: none; | ||
| 79 | border: none; | ||
| 80 | outline: 0; | ||
| 81 | text-align: center; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | .mask { | ||
| 85 | .position(); | ||
| 86 | z-index: 2101; | ||
| 87 | transition: opacity 500ms; | ||
| 88 | background-color: #000; | ||
| 89 | opacity: 0; | ||
| 90 | &.opacity { | ||
| 91 | opacity: 0.8; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | .gesture-mask { | ||
| 95 | .position(); | ||
| 96 | bottom: 61px; | ||
| 97 | z-index: 2103; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | </style> | ||
| 101 | |||
| 102 | <script> | ||
| 103 | export default { | ||
| 104 | name: "imageClipper", | ||
| 105 | props: { | ||
| 106 | img: String, //url或dataUrl | ||
| 107 | clipperImgWidth: { | ||
| 108 | type: Number, | ||
| 109 | default: 500 | ||
| 110 | }, | ||
| 111 | clipperImgHeight: { | ||
| 112 | type: Number, | ||
| 113 | default: 200 | ||
| 114 | } | ||
| 115 | }, | ||
| 116 | watch: { | ||
| 117 | img() { | ||
| 118 | this.loadImgQueue.push(this.img); | ||
| 119 | this._loadImg(); | ||
| 120 | } | ||
| 121 | }, | ||
| 122 | data() { | ||
| 123 | return { | ||
| 124 | originXDiff: 0, //裁剪canvas与原图canvas坐标原点上的差值 | ||
| 125 | originYDiff: 0, | ||
| 126 | |||
| 127 | maskShow: true, | ||
| 128 | maskShowTimer: null, | ||
| 129 | |||
| 130 | ctx: null, | ||
| 131 | pCtx: null, | ||
| 132 | |||
| 133 | actionBarHeight: 61, | ||
| 134 | |||
| 135 | loadImgQueue: [], //加载图片队列 | ||
| 136 | $img: null, | ||
| 137 | imgLoaded: false, | ||
| 138 | imgLoading: false, | ||
| 139 | imgStartWidth: null, | ||
| 140 | imgStartHeight: null, | ||
| 141 | imgCurrentWidth: null, | ||
| 142 | imgCurrentHeight: null, | ||
| 143 | imgX: null, //img对于canvas的坐标 | ||
| 144 | imgY: null, | ||
| 145 | imgScale: 1, //图片目前的缩放倍数 范围是1-5 | ||
| 146 | imgMinScale: 1, | ||
| 147 | imgMaxScale: 5, | ||
| 148 | imgScaleStep: 60, //缩放步长,每60px加减0.1 | ||
| 149 | |||
| 150 | //图片canvas宽高 | ||
| 151 | cWidth: 0, | ||
| 152 | cHeight: 0 | ||
| 153 | }; | ||
| 154 | }, | ||
| 155 | mounted() { | ||
| 156 | setTimeout(() => { | ||
| 157 | this._initClipper(); | ||
| 158 | }, 10); | ||
| 159 | }, | ||
| 160 | beforeDestroy() { | ||
| 161 | let $gesture = this.$refs.gesture; | ||
| 162 | |||
| 163 | $gesture.ontouchstart = null; | ||
| 164 | $gesture.ontouchmove = null; | ||
| 165 | $gesture.outouchend = null; | ||
| 166 | }, | ||
| 167 | methods: { | ||
| 168 | _initClipper() { | ||
| 169 | this.loadImgQueue.push(this.img); | ||
| 170 | this._initCanvas(); | ||
| 171 | this._loadImg(); | ||
| 172 | this._initEvent(); | ||
| 173 | }, | ||
| 174 | _initCanvas() { | ||
| 175 | let $canvas = this.$refs.canvas, | ||
| 176 | $pCanvas = this.$refs.pCanvas, | ||
| 177 | clipperClientRect = this.$refs.clipper.getBoundingClientRect(), | ||
| 178 | clipperWidth = parseInt(this.clipperImgWidth / window.devicePixelRatio), | ||
| 179 | clipperHeight = parseInt( | ||
| 180 | this.clipperImgHeight / window.devicePixelRatio | ||
| 181 | ); | ||
| 182 | |||
| 183 | this.ctx = $canvas.getContext("2d"); | ||
| 184 | this.pCtx = $pCanvas.getContext("2d"); | ||
| 185 | |||
| 186 | //判断clipperWidth与clipperHeight有没有超过容器值 | ||
| 187 | // if (clipperWidth < 0 || clipperWidth > clipperClientRect.width) { | ||
| 188 | // clipperWidth = 250 | ||
| 189 | // } | ||
| 190 | |||
| 191 | clipperWidth = clipperClientRect.width; | ||
| 192 | clipperHeight = clipperWidth / 1.375; | ||
| 193 | |||
| 194 | // if (clipperHeight < 0 || clipperHeight > clipperClientRect.height) { | ||
| 195 | // clipperHeight = 100 | ||
| 196 | // } | ||
| 197 | |||
| 198 | //因为canvas在手机上会被放大,因此里面的内容会模糊,这里根据手机的devicePixelRatio来放大canvas,然后再通过设置css来收缩,因此关于canvas的所有值或坐标都要乘以devicePixelRatio | ||
| 199 | $canvas.style.width = clipperClientRect.width + "px"; | ||
| 200 | $canvas.style.height = clipperClientRect.height + "px"; | ||
| 201 | $canvas.width = this._ratio(clipperClientRect.width); | ||
| 202 | $canvas.height = this._ratio(clipperClientRect.height); | ||
| 203 | |||
| 204 | $pCanvas.style.width = clipperWidth + "px"; | ||
| 205 | $pCanvas.style.height = clipperHeight + "px"; | ||
| 206 | $pCanvas.width = this._ratio(clipperWidth); | ||
| 207 | $pCanvas.height = this._ratio(clipperHeight); | ||
| 208 | |||
| 209 | //计算两个canvas原点的x y差值 | ||
| 210 | let cClientRect = $canvas.getBoundingClientRect(), | ||
| 211 | pClientRect = $pCanvas.getBoundingClientRect(); | ||
| 212 | |||
| 213 | this.originXDiff = pClientRect.left - cClientRect.left; | ||
| 214 | this.originYDiff = pClientRect.top - cClientRect.top; | ||
| 215 | this.cWidth = cClientRect.width; | ||
| 216 | this.cHeight = cClientRect.height; | ||
| 217 | }, | ||
| 218 | _initEvent() { | ||
| 219 | let $gesture = this.$refs.gesture, | ||
| 220 | cClientRect = this.$refs.canvas.getBoundingClientRect(), | ||
| 221 | scx = 0, //对于单手操作是移动的起点坐标,对于缩放是图片距离两手指的中点最近的图标。 | ||
| 222 | scy = 0, | ||
| 223 | fingers = {}; //记录当前有多少只手指在触控屏幕 | ||
| 224 | |||
| 225 | //one finger | ||
| 226 | let iX = this.imgX, | ||
| 227 | iY = this.imgY; | ||
| 228 | |||
| 229 | //two finger | ||
| 230 | let figureDistance = 0, | ||
| 231 | pinchScale = this.imgScale; | ||
| 232 | |||
| 233 | $gesture.addEventListener( | ||
| 234 | "touchstart", | ||
| 235 | e => { | ||
| 236 | if (!this.imgLoaded) { | ||
| 237 | return; | ||
| 238 | } | ||
| 239 | |||
| 240 | if (e.touches.length === 1) { | ||
| 241 | let finger = e.touches[0]; | ||
| 242 | |||
| 243 | scx = finger.pageX; | ||
| 244 | scy = finger.pageY; | ||
| 245 | iX = this.imgX; | ||
| 246 | iY = this.imgY; | ||
| 247 | fingers[finger.identifier] = finger; | ||
| 248 | } else if (e.touches.length === 2) { | ||
| 249 | let finger1 = e.touches[0], | ||
| 250 | finger2 = e.touches[1], | ||
| 251 | f1x = finger1.pageX - cClientRect.left, | ||
| 252 | f1y = finger1.pageY - cClientRect.top, | ||
| 253 | f2x = finger2.pageX - cClientRect.left, | ||
| 254 | f2y = finger2.pageY - cClientRect.top; | ||
| 255 | |||
| 256 | scx = parseInt((f1x + f2x) / 2); | ||
| 257 | scy = parseInt((f1y + f2y) / 2); | ||
| 258 | figureDistance = this._pointDistance(f1x, f1y, f2x, f2y); | ||
| 259 | fingers[finger1.identifier] = finger1; | ||
| 260 | fingers[finger2.identifier] = finger2; | ||
| 261 | |||
| 262 | //判断变换中点是否在图片中,如果不是则去离图片最近的点 | ||
| 263 | if (scx < this.imgX) { | ||
| 264 | scx = this.imgX; | ||
| 265 | } | ||
| 266 | if (scx > this.imgX + this.imgCurrentWidth) { | ||
| 267 | scx = this.imgX + this.imgCurrentHeight; | ||
| 268 | } | ||
| 269 | if (scy < this.imgY) { | ||
| 270 | scy = this.imgY; | ||
| 271 | } | ||
| 272 | if (scy > this.imgY + this.imgCurrentHeight) { | ||
| 273 | scy = this.imgY + this.imgCurrentHeight; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | }, | ||
| 277 | false | ||
| 278 | ); | ||
| 279 | $gesture.addEventListener( | ||
| 280 | "touchmove", | ||
| 281 | e => { | ||
| 282 | e.preventDefault(); | ||
| 283 | |||
| 284 | if (!this.imgLoaded) { | ||
| 285 | return; | ||
| 286 | } | ||
| 287 | |||
| 288 | this.maskShowTimer && clearTimeout(this.maskShowTimer); | ||
| 289 | this.maskShow = false; | ||
| 290 | |||
| 291 | if (e.touches.length === 1) { | ||
| 292 | let f1x = e.touches[0].pageX, | ||
| 293 | f1y = e.touches[0].pageY; | ||
| 294 | this._drawImage( | ||
| 295 | iX + f1x - scx, | ||
| 296 | iY + f1y - scy, | ||
| 297 | this.imgCurrentWidth, | ||
| 298 | this.imgCurrentHeight | ||
| 299 | ); | ||
| 300 | } else if (e.touches.length === 2) { | ||
| 301 | let finger1 = e.touches[0], | ||
| 302 | finger2 = e.touches[1], | ||
| 303 | f1x = finger1.pageX - cClientRect.left, | ||
| 304 | f1y = finger1.pageY - cClientRect.top, | ||
| 305 | f2x = finger2.pageX - cClientRect.left, | ||
| 306 | f2y = finger2.pageY - cClientRect.top, | ||
| 307 | newFigureDistance = this._pointDistance(f1x, f1y, f2x, f2y), | ||
| 308 | scale = | ||
| 309 | this.imgScale + | ||
| 310 | parseFloat( | ||
| 311 | ( | ||
| 312 | (newFigureDistance - figureDistance) / | ||
| 313 | this.imgScaleStep | ||
| 314 | ).toFixed(1) | ||
| 315 | ); | ||
| 316 | |||
| 317 | fingers[finger1.identifier] = finger1; | ||
| 318 | fingers[finger2.identifier] = finger2; | ||
| 319 | |||
| 320 | if (scale !== pinchScale) { | ||
| 321 | //目前缩放的最小比例是1,最大是5 | ||
| 322 | if (scale < this.imgMinScale) { | ||
| 323 | scale = this.imgMinScale; | ||
| 324 | } else if (scale > this.imgMaxScale) { | ||
| 325 | scale = this.imgMaxScale; | ||
| 326 | } | ||
| 327 | |||
| 328 | pinchScale = scale; | ||
| 329 | this._scale(scx, scy, scale); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | }, | ||
| 333 | false | ||
| 334 | ); | ||
| 335 | $gesture.addEventListener("touchend", e => { | ||
| 336 | if (!this.imgLoaded) { | ||
| 337 | return; | ||
| 338 | } | ||
| 339 | |||
| 340 | this.imgScale = pinchScale; | ||
| 341 | |||
| 342 | //从finger删除已经离开的手指 | ||
| 343 | let touches = Array.prototype.slice.call(e.changedTouches, 0); | ||
| 344 | |||
| 345 | touches.forEach(item => { | ||
| 346 | delete fingers[item.identifier]; | ||
| 347 | }); | ||
| 348 | |||
| 349 | //迭代fingers,如果存在finger则更新scx,scy,iX,iY,因为可能缩放后立即单指拖动 | ||
| 350 | let i, | ||
| 351 | fingerArr = []; | ||
| 352 | |||
| 353 | for (i in fingers) { | ||
| 354 | if (fingers.hasOwnProperty(i)) { | ||
| 355 | fingerArr.push(fingers[i]); | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | if (fingerArr.length > 0) { | ||
| 360 | scx = fingerArr[0].pageX; | ||
| 361 | scy = fingerArr[0].pageY; | ||
| 362 | iX = this.imgX; | ||
| 363 | iY = this.imgY; | ||
| 364 | } else { | ||
| 365 | this.maskShowTimer = setTimeout(() => { | ||
| 366 | this.maskShow = true; | ||
| 367 | }, 300); | ||
| 368 | } | ||
| 369 | |||
| 370 | //做边界值检测 | ||
| 371 | let x = this.imgX, | ||
| 372 | y = this.imgY, | ||
| 373 | pClientRect = this.$refs.pCanvas.getBoundingClientRect(); | ||
| 374 | |||
| 375 | if (x > pClientRect.left + pClientRect.width) { | ||
| 376 | x = pClientRect.left; | ||
| 377 | } else if (x + this.imgCurrentWidth < pClientRect.left) { | ||
| 378 | x = pClientRect.left + pClientRect.width - this.imgCurrentWidth; | ||
| 379 | } | ||
| 380 | |||
| 381 | if (y > pClientRect.top + pClientRect.height) { | ||
| 382 | y = pClientRect.top; | ||
| 383 | } else if (y + this.imgCurrentHeight < pClientRect.top) { | ||
| 384 | y = pClientRect.top + pClientRect.height - this.imgCurrentHeight; | ||
| 385 | } | ||
| 386 | |||
| 387 | if (this.imgX !== x || this.imgY !== y) { | ||
| 388 | this._drawImage(x, y, this.imgCurrentWidth, this.imgCurrentHeight); | ||
| 389 | } | ||
| 390 | }); | ||
| 391 | }, | ||
| 392 | _loadImg() { | ||
| 393 | if (this.imgLoading || this.loadImgQueue.length === 0) { | ||
| 394 | return; | ||
| 395 | } | ||
| 396 | |||
| 397 | let img = this.loadImgQueue.shift(); | ||
| 398 | |||
| 399 | if (!img) { | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | |||
| 403 | let $img = new Image(), | ||
| 404 | onLoad = e => { | ||
| 405 | $img.removeEventListener("load", onLoad, false); | ||
| 406 | this.$img = $img; | ||
| 407 | this.imgLoaded = true; | ||
| 408 | this.imgLoading = false; | ||
| 409 | |||
| 410 | this._initImg($img.width, $img.height); | ||
| 411 | this.$emit("loadSuccess", e); | ||
| 412 | this.$emit("loadComplete", e); | ||
| 413 | this._loadImg(); | ||
| 414 | }, | ||
| 415 | onError = e => { | ||
| 416 | $img.removeEventListener("error", onError, false); | ||
| 417 | this.$img = $img = null; | ||
| 418 | this.imgLoading = false; | ||
| 419 | |||
| 420 | // this.$emit('loadError', e); | ||
| 421 | // this.$emit('loadComplete', e); | ||
| 422 | this._loadImg(); | ||
| 423 | }; | ||
| 424 | |||
| 425 | this.$emit("beforeLoad"); | ||
| 426 | this.imgLoading = true; | ||
| 427 | this.imgLoaded = false; | ||
| 428 | $img.src = this.img; | ||
| 429 | $img.crossOrigin = "Anonymous"; //因为canvas toDataUrl不能操作未经允许的跨域图片,这需要服务器设置Access-Control-Allow-Origin头 | ||
| 430 | $img.addEventListener("load", onLoad, false); | ||
| 431 | $img.addEventListener("error", onError, false); | ||
| 432 | }, | ||
| 433 | _initImg(w, h) { | ||
| 434 | let eW = null, | ||
| 435 | eH = null, | ||
| 436 | maxW = this.cWidth, | ||
| 437 | maxH = this.cHeight - this.actionBarHeight; | ||
| 438 | |||
| 439 | // console.log("this.cWidth===", this.cWidth) | ||
| 440 | // console.log("this.cHeight===", this.cHeight) | ||
| 441 | // console.log("this.actionBarHeight===", this.actionBarHeight) | ||
| 442 | |||
| 443 | if (w < maxW && h < maxH) { | ||
| 444 | if (w > 1.375 * h) { | ||
| 445 | eH = maxH; | ||
| 446 | eW = (w / h) * maxH; | ||
| 447 | } else { | ||
| 448 | eW = maxW; | ||
| 449 | eH = (h / w) * maxW; | ||
| 450 | } | ||
| 451 | } else { | ||
| 452 | //如果图片的宽高都少于容器的宽高,则不做处理 | ||
| 453 | if (w <= maxW && h <= maxH) { | ||
| 454 | eW = w; | ||
| 455 | eH = h; | ||
| 456 | } else if (w > maxW && h <= maxH) { | ||
| 457 | eW = maxW; | ||
| 458 | eH = parseInt((h / w) * maxW); | ||
| 459 | } else if (w <= maxW && h > maxH) { | ||
| 460 | eW = parseInt((w / h) * maxH); | ||
| 461 | eH = maxH; | ||
| 462 | } else { | ||
| 463 | //判断是横图还是竖图 | ||
| 464 | if (h > w) { | ||
| 465 | eW = parseInt((w / h) * maxH); | ||
| 466 | eH = maxH; | ||
| 467 | } else { | ||
| 468 | eW = maxW; | ||
| 469 | eH = parseInt((h / w) * maxW); | ||
| 470 | } | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | // if (eW <= maxW && eH <= maxH) { | ||
| 475 | //记录其初始化的宽高,日后的缩放功能以此值为基础 | ||
| 476 | this.imgStartWidth = eW; | ||
| 477 | this.imgStartHeight = eH; | ||
| 478 | this._drawImage((maxW - eW) / 2, (maxH - eH) / 2, eW, eH); | ||
| 479 | // } else { | ||
| 480 | // this._initImg(eW, eH); | ||
| 481 | // } | ||
| 482 | }, | ||
| 483 | _drawImage(x, y, w, h) { | ||
| 484 | this._clearCanvas(); | ||
| 485 | this.imgX = parseInt(x); | ||
| 486 | this.imgY = parseInt(y); | ||
| 487 | this.imgCurrentWidth = parseInt(w); | ||
| 488 | this.imgCurrentHeight = parseInt(h); | ||
| 489 | |||
| 490 | //更新canvas | ||
| 491 | this.ctx.drawImage( | ||
| 492 | this.$img, | ||
| 493 | this._ratio(x), | ||
| 494 | this._ratio(y), | ||
| 495 | this._ratio(w), | ||
| 496 | this._ratio(h) | ||
| 497 | ); | ||
| 498 | |||
| 499 | //更新pCanvas,只需要减去两个canvas坐标原点对应的差值即可 | ||
| 500 | this.pCtx.drawImage( | ||
| 501 | this.$img, | ||
| 502 | this._ratio(x - this.originXDiff), | ||
| 503 | this._ratio(y - this.originYDiff), | ||
| 504 | this._ratio(w), | ||
| 505 | this._ratio(h) | ||
| 506 | ); | ||
| 507 | }, | ||
| 508 | _clearCanvas() { | ||
| 509 | let $canvas = this.$refs.canvas, | ||
| 510 | $pCanvas = this.$refs.pCanvas; | ||
| 511 | |||
| 512 | $canvas.width = $canvas.width; | ||
| 513 | $canvas.height = $canvas.height; | ||
| 514 | $pCanvas.width = $pCanvas.width; | ||
| 515 | $pCanvas.height = $pCanvas.height; | ||
| 516 | }, | ||
| 517 | _ratio(size) { | ||
| 518 | return parseInt(window.devicePixelRatio * size); | ||
| 519 | }, | ||
| 520 | _pointDistance(x1, y1, x2, y2) { | ||
| 521 | return parseInt(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))); | ||
| 522 | }, | ||
| 523 | _scale(x, y, scale) { | ||
| 524 | let newPicWidth = parseInt(this.imgStartWidth * scale), | ||
| 525 | newPicHeight = parseInt(this.imgStartHeight * scale), | ||
| 526 | newIX = parseInt( | ||
| 527 | x - (newPicWidth * (x - this.imgX)) / this.imgCurrentWidth | ||
| 528 | ), | ||
| 529 | newIY = parseInt( | ||
| 530 | y - (newPicHeight * (y - this.imgY)) / this.imgCurrentHeight | ||
| 531 | ); | ||
| 532 | |||
| 533 | this._drawImage(newIX, newIY, newPicWidth, newPicHeight); | ||
| 534 | }, | ||
| 535 | _clipper() { | ||
| 536 | let imgData = null; | ||
| 537 | |||
| 538 | try { | ||
| 539 | imgData = this.$refs.pCanvas.toDataURL(); | ||
| 540 | } catch (e) { | ||
| 541 | console.error( | ||
| 542 | "请在response header加上Access-Control-Allow-Origin,否则canvas无法裁剪未经许可的跨域图片" | ||
| 543 | ); | ||
| 544 | } | ||
| 545 | this.$emit("ok", imgData); | ||
| 546 | }, | ||
| 547 | _cancel() { | ||
| 548 | this.$emit("cancel"); | ||
| 549 | }, | ||
| 550 | |||
| 551 | //public | ||
| 552 | getBase64(dataURL) { | ||
| 553 | return dataURL.replace(/^data:image\/(png|jpg);base64,/, ""); | ||
| 554 | } | ||
| 555 | } | ||
| 556 | }; | ||
| 557 | </script> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | <template> | 1 | <template> |
| 2 | <div> | 2 | <div> |
| 3 | <div class="img-container" v-for="(item,index) in fileList" :key="index"> | 3 | <div class="img-container" v-for="(item,index) in fileList" :key="index"> |
| 4 | <img :src="item.worksUrl" /> | 4 | <img v-if="item.worksType=='pic'" :src="item.worksUrl" /> |
| 5 | <video v-if="item.worksType=='video'" controls> | ||
| 6 | <source :src="item.worksUrl" type="video/mp4" /> | ||
| 7 | </video> | ||
| 5 | <i class="van-icon van-icon-delete" @click="deleteImageHandler(index)"></i> | 8 | <i class="van-icon van-icon-delete" @click="deleteImageHandler(index)"></i> |
| 6 | </div> | 9 | </div> |
| 7 | <van-uploader | 10 | <van-uploader |
| 8 | ref="vanUploader" | 11 | ref="vanUploader" |
| 9 | class="uploader" | 12 | class="uploader" |
| 13 | accept="image/*, audio/mp4, video/mp4" | ||
| 14 | :before-read="beforeUpload" | ||
| 10 | :after-read="uploadSumit" | 15 | :after-read="uploadSumit" |
| 11 | v-if="!fileList || fileList.length < 3" | 16 | v-if="!fileList || fileList.length < 3" |
| 12 | >+</van-uploader> | 17 | >+</van-uploader> |
| 18 | |||
| 19 | <image-clipper | ||
| 20 | ref="clipper" | ||
| 21 | v-if="imageData.show" | ||
| 22 | :img="imageData.data" | ||
| 23 | :clipper-img-width="750" | ||
| 24 | :clipper-img-height="537" | ||
| 25 | @ok="imageClipperHandler" | ||
| 26 | @cancel="imageData.show=false" | ||
| 27 | ></image-clipper> | ||
| 13 | </div> | 28 | </div> |
| 14 | </template> | 29 | </template> |
| 15 | 30 | ||
| 16 | 31 | ||
| 17 | 32 | ||
| 18 | <script> | 33 | <script> |
| 19 | import { request } from "@/api/fetch-api.js"; | 34 | import { request, httpPost } from "@/api/fetch-api.js"; |
| 35 | import ImageClipper from "./ImageClipper"; | ||
| 20 | 36 | ||
| 21 | import Vue from "vue"; | 37 | import Vue from "vue"; |
| 22 | import { Uploader } from "vant"; | 38 | import { Uploader } from "vant"; |
| 39 | import { Toast } from "vant"; | ||
| 23 | Vue.use(Uploader); | 40 | Vue.use(Uploader); |
| 41 | Vue.use(Toast); | ||
| 24 | 42 | ||
| 25 | /** | 43 | /** |
| 26 | * 外层插件可通过监听:v-on:before-upload;v-on:after-upload两个事件监听上传结果 | 44 | * 外层插件可通过监听:v-on:before-upload;v-on:after-upload两个事件监听上传结果 |
| ... | @@ -32,27 +50,85 @@ export default { | ... | @@ -32,27 +50,85 @@ export default { |
| 32 | data() { | 50 | data() { |
| 33 | return { | 51 | return { |
| 34 | fileList: this.value, | 52 | fileList: this.value, |
| 35 | uploadUrl: "https://api.k.wxpai.cn/bizproxy/kdapi/file/upload", | 53 | uploadFile: "https://api.k.wxpai.cn/bizproxy/kdapi/file/upload", |
| 54 | uploadUrl: "https://api.k.wxpai.cn/bizproxy/kdapi/file/uploadBase64", | ||
| 55 | imageData: { | ||
| 56 | show: false, | ||
| 57 | data: "" | ||
| 58 | } | ||
| 36 | }; | 59 | }; |
| 37 | }, | 60 | }, |
| 38 | methods: { | 61 | methods: { |
| 62 | beforeUpload(params) { | ||
| 63 | // console.log(params); | ||
| 64 | // let worksType = params.type.indexOf("image") >= 0 ? "pic" : "video"; | ||
| 65 | // if ( | ||
| 66 | // worksType == "video" && | ||
| 67 | // (!this.fileList || this.fileList.length == 0) | ||
| 68 | // ) { | ||
| 69 | // Toast("第一个作品必须上传图片!"); | ||
| 70 | // return false; | ||
| 71 | // } | ||
| 72 | return true; | ||
| 73 | }, | ||
| 39 | uploadSumit(params) { | 74 | uploadSumit(params) { |
| 40 | console.log(params); | 75 | console.log(params); |
| 76 | let worksType = params.file.type.indexOf("image") >= 0 ? "pic" : "video"; | ||
| 77 | if (worksType == "pic") { | ||
| 78 | this.imageData.data = params.content; | ||
| 79 | this.imageData.show = true; | ||
| 80 | } else { | ||
| 81 | Toast.loading({ | ||
| 82 | mask: true, | ||
| 83 | forbidClick: true, | ||
| 84 | message: "视频提交中..." | ||
| 85 | }); | ||
| 86 | let data = { | ||
| 87 | path: "/pro/jiajiaChildrenHost/works", | ||
| 88 | file: params.file | ||
| 89 | }; | ||
| 90 | request | ||
| 91 | .form(this.uploadFile, data) | ||
| 92 | .then(result => { | ||
| 93 | Toast.clear(); | ||
| 94 | let uploadResult = { | ||
| 95 | worksUrl: result.data.content, | ||
| 96 | worksType: "video" | ||
| 97 | }; | ||
| 98 | if (!this.fileList) { | ||
| 99 | this.fileList = []; | ||
| 100 | } | ||
| 101 | this.fileList.push(uploadResult); | ||
| 102 | this.$emit("input", this.fileList); | ||
| 103 | }) | ||
| 104 | .catch(res => {}); | ||
| 105 | } | ||
| 106 | }, | ||
| 107 | imageClipperHandler(base64) { | ||
| 41 | let data = { | 108 | let data = { |
| 42 | path: "/pro/jiajiaChildrenHost/works", | 109 | path: "/pro/jiajiaChildrenHost/works", |
| 43 | file: params.file | 110 | data: base64 |
| 44 | }; | 111 | }; |
| 45 | request | 112 | |
| 46 | .form(this.uploadUrl, data) | 113 | Toast.loading({ |
| 114 | mask: true, | ||
| 115 | forbidClick: true, | ||
| 116 | message: "图片提交中..." | ||
| 117 | }); | ||
| 118 | httpPost({ url: this.uploadUrl, data: data }) | ||
| 47 | .then(result => { | 119 | .then(result => { |
| 120 | Toast.clear(); | ||
| 121 | console.log(result); | ||
| 48 | let uploadResult = { | 122 | let uploadResult = { |
| 49 | worksUrl: result.data.content, | 123 | worksUrl: result, |
| 50 | worksType: params.file.type.indexOf("image") >= 0 ? "pic" : "video" | 124 | worksType: "pic" |
| 51 | }; | 125 | }; |
| 52 | if (!this.fileList) { | 126 | if (!this.fileList) { |
| 53 | this.fileList = []; | 127 | this.fileList = []; |
| 54 | } | 128 | } |
| 55 | this.fileList.push(uploadResult); | 129 | this.fileList.push(uploadResult); |
| 130 | console.log("submit image : ", this.fileList); | ||
| 131 | this.imageData.show = false; | ||
| 56 | this.$emit("input", this.fileList); | 132 | this.$emit("input", this.fileList); |
| 57 | }) | 133 | }) |
| 58 | .catch(res => {}); | 134 | .catch(res => {}); |
| ... | @@ -65,6 +141,9 @@ export default { | ... | @@ -65,6 +141,9 @@ export default { |
| 65 | currentValue: function() { | 141 | currentValue: function() { |
| 66 | return this.value; | 142 | return this.value; |
| 67 | } | 143 | } |
| 144 | }, | ||
| 145 | components: { | ||
| 146 | ImageClipper | ||
| 68 | } | 147 | } |
| 69 | }; | 148 | }; |
| 70 | </script> | 149 | </script> |
| ... | @@ -99,6 +178,9 @@ export default { | ... | @@ -99,6 +178,9 @@ export default { |
| 99 | img { | 178 | img { |
| 100 | width: 100%; | 179 | width: 100%; |
| 101 | } | 180 | } |
| 181 | video { | ||
| 182 | width: 100%; | ||
| 183 | } | ||
| 102 | 184 | ||
| 103 | .van-icon { | 185 | .van-icon { |
| 104 | background-color: rgba($color: #000000, $alpha: 0.3); | 186 | background-color: rgba($color: #000000, $alpha: 0.3); | ... | ... |
| ... | @@ -11,9 +11,16 @@ | ... | @@ -11,9 +11,16 @@ |
| 11 | </div> | 11 | </div> |
| 12 | <div class="swipe"> | 12 | <div class="swipe"> |
| 13 | <van-swipe :autoplay="5000"> | 13 | <van-swipe :autoplay="5000"> |
| 14 | <van-swipe-item v-for="(works, index) in formData.worksList" :key="index"> | 14 | <van-swipe-item v-for="(item, index) in formData.worksList" :key="index"> |
| 15 | <!-- <img :src="works.worksUrl" /> --> | 15 | <!-- <img :src="works.worksUrl" /> --> |
| 16 | <div class="img" v-bind:style="{backgroundImage:'url(' + works.worksUrl + ')'}"></div> | 16 | <div |
| 17 | v-if="item.worksType=='pic'" | ||
| 18 | class="img" | ||
| 19 | v-bind:style="{backgroundImage:'url(' + item.worksUrl + ')'}" | ||
| 20 | ></div> | ||
| 21 | <video v-if="item.worksType=='video'" controls> | ||
| 22 | <source :src="item.worksUrl" type="video/mp4" /> | ||
| 23 | </video> | ||
| 17 | </van-swipe-item> | 24 | </van-swipe-item> |
| 18 | </van-swipe> | 25 | </van-swipe> |
| 19 | </div> | 26 | </div> |
| ... | @@ -171,6 +178,11 @@ export default { | ... | @@ -171,6 +178,11 @@ export default { |
| 171 | width: 630px; | 178 | width: 630px; |
| 172 | background-size: cover; | 179 | background-size: cover; |
| 173 | } | 180 | } |
| 181 | |||
| 182 | video { | ||
| 183 | height: 451px; | ||
| 184 | width: 630px; | ||
| 185 | } | ||
| 174 | } | 186 | } |
| 175 | 187 | ||
| 176 | .space { | 188 | .space { | ... | ... |
| ... | @@ -9,7 +9,13 @@ | ... | @@ -9,7 +9,13 @@ |
| 9 | v-on:praiseSuccess="showPraiseSuccessModel" | 9 | v-on:praiseSuccess="showPraiseSuccessModel" |
| 10 | v-on:showShare="shareModelVisiable=true" | 10 | v-on:showShare="shareModelVisiable=true" |
| 11 | ></ViewModel> | 11 | ></ViewModel> |
| 12 | <EditModel v-model="formData" v-if="init && formEdit" v-on:submit="showSuccessModel"></EditModel> | 12 | <EditModel |
| 13 | v-model="formData" | ||
| 14 | v-if="init && formEdit" | ||
| 15 | v-on:submit="submitSuccessHandler" | ||
| 16 | v-on:agreement="showAgreementModel" | ||
| 17 | v-on:privacy="showPrivacyModel" | ||
| 18 | ></EditModel> | ||
| 13 | 19 | ||
| 14 | <div class="bottom-line"></div> | 20 | <div class="bottom-line"></div> |
| 15 | 21 | ||
| ... | @@ -100,23 +106,38 @@ export default { | ... | @@ -100,23 +106,38 @@ export default { |
| 100 | this.initShare(); | 106 | this.initShare(); |
| 101 | }); | 107 | }); |
| 102 | }, | 108 | }, |
| 103 | showSuccessModel() { | 109 | submitSuccessHandler(data) { |
| 104 | this.model.title = "温馨提示"; | 110 | if (data.isFirst) { |
| 105 | this.model.content = "报名已成功!"; | 111 | this.model.title = "温馨提示"; |
| 106 | this.model.index = "default"; | 112 | this.model.content = "报名已成功!获得1次抽奖机会"; |
| 107 | this.model.btnShow = true; | 113 | this.model.index = "default"; |
| 108 | this.model.btnText = "查看我的主页"; | 114 | this.model.btnShow = true; |
| 109 | this.model.show = true; | 115 | this.model.btnText = "前往抽奖"; |
| 110 | 116 | this.model.show = true; | |
| 111 | let that = this; | 117 | |
| 112 | this.model.confirmHandler = function() { | 118 | let that = this; |
| 113 | that.initActivity(); | 119 | this.model.confirmHandler = function() { |
| 114 | }; | 120 | that.$router.push("/draw"); |
| 121 | }; | ||
| 122 | } else { | ||
| 123 | this.model.title = "温馨提示"; | ||
| 124 | this.model.content = "作品信息修改成功!"; | ||
| 125 | this.model.index = "default"; | ||
| 126 | this.model.btnShow = true; | ||
| 127 | this.model.btnText = "查看我的主页"; | ||
| 128 | this.model.show = true; | ||
| 129 | |||
| 130 | let that = this; | ||
| 131 | this.model.confirmHandler = function() { | ||
| 132 | that.initActivity(); | ||
| 133 | }; | ||
| 134 | } | ||
| 115 | }, | 135 | }, |
| 116 | showPraiseSuccessModel() { | 136 | showPraiseSuccessModel() { |
| 117 | this.model.show = true; | 137 | this.model.show = true; |
| 118 | this.model.title = "点赞成功"; | 138 | this.model.title = "点赞成功"; |
| 119 | this.model.content = "您已获得一次抽奖机会"; | 139 | this.model.content = "您已获得一次抽奖机会"; |
| 140 | this.model.index = "default"; | ||
| 120 | this.model.btnShow = true; | 141 | this.model.btnShow = true; |
| 121 | this.model.btnText = "前往抽奖"; | 142 | this.model.btnText = "前往抽奖"; |
| 122 | 143 | ||
| ... | @@ -130,6 +151,14 @@ export default { | ... | @@ -130,6 +151,14 @@ export default { |
| 130 | that.initActivity(); | 151 | that.initActivity(); |
| 131 | }; | 152 | }; |
| 132 | }, | 153 | }, |
| 154 | showAgreementModel() { | ||
| 155 | this.model.index = "agreement"; | ||
| 156 | this.model.show = true; | ||
| 157 | }, | ||
| 158 | showPrivacyModel() { | ||
| 159 | this.model.index = "privacy"; | ||
| 160 | this.model.show = true; | ||
| 161 | }, | ||
| 133 | initShare() { | 162 | initShare() { |
| 134 | let link = location.origin + location.pathname; | 163 | let link = location.origin + location.pathname; |
| 135 | if (this.formData.worksCode) { | 164 | if (this.formData.worksCode) { | ... | ... |
| ... | @@ -73,7 +73,7 @@ const router = new Router({ | ... | @@ -73,7 +73,7 @@ const router = new Router({ |
| 73 | 73 | ||
| 74 | router.beforeEach((to, from, next) => { | 74 | router.beforeEach((to, from, next) => { |
| 75 | let link = location.origin + location.pathname; | 75 | let link = location.origin + location.pathname; |
| 76 | as.setShare(link, null, null, null); | 76 | as.setShare(link, "", "", ""); |
| 77 | const title = to.meta && to.meta.title; | 77 | const title = to.meta && to.meta.title; |
| 78 | if (title) { | 78 | if (title) { |
| 79 | document.title = title; | 79 | document.title = title; | ... | ... |
| ... | @@ -38,8 +38,8 @@ module.exports = { | ... | @@ -38,8 +38,8 @@ module.exports = { |
| 38 | 38 | ||
| 39 | // 它支持webPack-dev-server的所有选项 | 39 | // 它支持webPack-dev-server的所有选项 |
| 40 | devServer: { | 40 | devServer: { |
| 41 | host: "192.168.0.101", | 41 | // host: "192.168.0.101", |
| 42 | // host: "localhost", | 42 | host: "localhost", |
| 43 | port: 9001, // 端口号 | 43 | port: 9001, // 端口号 |
| 44 | https: false, // https:{type:Boolean} | 44 | https: false, // https:{type:Boolean} |
| 45 | open: true, //配置自动启动浏览器 | 45 | open: true, //配置自动启动浏览器 | ... | ... |
-
Please register or sign in to post a comment