1054 lines
33 KiB
Vue
1054 lines
33 KiB
Vue
<template>
|
||
<Layout :index="-1" :banner="0" :img="'/static/img/about.jpg'" :titles="'个人中心'" :title_content="'个人中心'">
|
||
<view class="bg ptm-80">
|
||
<view class="content">
|
||
<view class="content_left">
|
||
<memberleft :index="'3'"></memberleft>
|
||
</view>
|
||
<view class="content_right">
|
||
<view class="mtitle">
|
||
<image src="../static/img/member/iconqq.png" class="mimg"></image>
|
||
游戏产品评估确权
|
||
</view>
|
||
<view class="lines"></view>
|
||
<view class="asset_list_desc">
|
||
<view class="assetDesc">
|
||
<view class="assetDesc_dian"></view>
|
||
采集与分析游戏研发、产权、运营等多维度数据,运用先进数据大模型精准评估游戏资产价值
|
||
</view>
|
||
<view class="assetDesc">
|
||
<view class="assetDesc_dian"></view>
|
||
借助区块链技术完成确权认证、质押过户、转让交易
|
||
</view>
|
||
<view class="assetDesc">
|
||
<view class="assetDesc_dian"></view>
|
||
有效解决游戏数字资产价值评估标准缺失、企业融资难、运营风险监管不透明以及不良资产处置专业度不足等问题
|
||
</view>
|
||
</view>
|
||
<view class="content_r">
|
||
<view class="d-b-c">
|
||
<view class="adds" @tap="asset_add()">
|
||
<image src="../static/img/member/add.png" class="addimg"></image>
|
||
新增
|
||
</view>
|
||
<view class="search-box d-c-c">
|
||
<input type="text" v-model="name" class="search-name" name="param" placeholder="请输入资产名称" value="" placeholder-class="search-names">
|
||
<view class="adds" id="btn_sub" @tap="getData()">
|
||
<image src="../static/img/member/ss.png" class="addimgs"></image>
|
||
搜索
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="qqtable">
|
||
<el-table
|
||
:data="listData"
|
||
:cell-style="{ textAlign: 'center', fontSize: '12px', color: '#1D2129'}"
|
||
class="center-table"
|
||
style="width: 100%">
|
||
<el-table-column
|
||
fixed
|
||
prop="no"
|
||
label="资产编号"
|
||
width="120">
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="name"
|
||
label="资产名称"
|
||
width="140">
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="province"
|
||
label="资产类型"
|
||
width="110">
|
||
<template slot-scope="scope">
|
||
<span>游戏数字资产包</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="username"
|
||
label="权属方"
|
||
width="120">
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="create_time"
|
||
label="提交时间"
|
||
width="90">
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="status"
|
||
label="状态"
|
||
width="100">
|
||
<template slot-scope="scope">
|
||
<span v-if="scope.row.status == 'draft'" >未提交</span>
|
||
<span v-if="scope.row.status == 'pending'" >审核中</span>
|
||
<span v-if="scope.row.status == 'pass'" class="green">审核成功</span>
|
||
<span v-if="scope.row.status == 'fail'" class="red">审核失败</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="tx_hash"
|
||
label="存证哈希">
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="contract_status_text"
|
||
label="签约状态"
|
||
width="90">
|
||
</el-table-column>
|
||
<el-table-column
|
||
fixed="right"
|
||
label="操作"
|
||
width="170">
|
||
<template slot-scope="scope">
|
||
<el-button @tap="goEdit(scope.row.id)" type="text" size="small" class="asset_e" v-if="scope.row.status== 'draft'">继续填写</el-button>
|
||
<el-button @tap="goEdit(scope.row.id)" type="text" size="small" class="asset_e" v-if="scope.row.status== 'pass'">更新申请表</el-button>
|
||
<el-button @tap="goEdit(scope.row.id)" type="text" size="small" class="asset_e" v-if="scope.row.status== 'fail'">修改</el-button>
|
||
<el-button @click="downloadPDF(scope.row.report_url)" type="text" size="small" class="asset_l" v-if="scope.row.status== 'pass'&&scope.row.report_url">查看评估报告</el-button>
|
||
<!-- <el-button @click="downloadPDF(scope.row.report_url)" type="text" size="small" class="asset_l" v-if="scope.row.status== 'pass'&&!scope.row.report_url">报告评估中</el-button> -->
|
||
<el-button @tap="finds(scope.row)" type="text" size="small" class="asset_l" v-if="scope.row.status== 'fail'">查看意见</el-button>
|
||
<el-button @tap="openAgreementDialog(scope.row)" type="text" size="small" class="asset_l" v-if="scope.row.status== 'pass'&&scope.row.contract_status=='unsigned'">评估服务签约</el-button>
|
||
<el-button @tap="openPayDialog(scope.row)" type="text" size="small" class="asset_l" v-if="scope.row.status== 'pass'&&scope.row.contract_status=='signed'">付费生产报告</el-button>
|
||
|
||
<el-button @tap="goEdit(scope.row.id)" type="text" size="small" class="asset_e" v-if="scope.row.status== 'pending'">查看申请表</el-button>
|
||
<el-button @tap="findqy(scope.row)" type="text" size="small" class="asset_l" v-if="scope.row.contract_status== 'failed'">查看意见</el-button>
|
||
<el-button @tap="openAgreementDialog(scope.row)" type="text" size="small" class="asset_l" v-if="scope.row.status== 'pass'&&scope.row.contract_status=='failed'">重新签约</el-button>
|
||
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</view>
|
||
<el-pagination v-if="total>10" background layout="prev, pager, next" :total="total" :current-page="page" :page-size="list_rows" @size-change="handleSizeChange" @current-change="handleCurrentChange"></el-pagination>
|
||
|
||
<!-- 评估服务签约弹窗 -->
|
||
<el-dialog
|
||
:visible.sync="agreementDialogVisible"
|
||
width="657px"
|
||
:close-on-click-modal="false"
|
||
top="135px"
|
||
custom-class="agreement-dialog-custom"
|
||
v-if="!signDialogVisible"
|
||
>
|
||
<div class="agreement-dialog-header">
|
||
<span class="agreement-dialog-title">评估服务协议</span>
|
||
</div>
|
||
<div class="agreement-content" style="max-height: 470px; overflow-y: auto; text-align: left;">
|
||
<div style="font-size: 14px; color: #3D3D3D; margin-top: 10px;">
|
||
协议编号:________________ <br/>
|
||
甲方(委托方):<br/>
|
||
统一社会信用代码:______________________________<br/>
|
||
联系地址:________________________________________<br/>
|
||
联系人/授权代表:__________________________________<br/>
|
||
法人身份证号:________________________________________<br/>
|
||
联系人电话:________________________________________<br/>
|
||
|
||
乙方(服务方):四川数字世界文化科技有限公司<br/>
|
||
统一社会信用代码:91510100MACHFBAG0L<br/>
|
||
联系地址:四川省成都市高新区盛兴街518号<br/>
|
||
联系人/授权代表:文本文本<br/>
|
||
法人身份证号:1111111111<br/>
|
||
联系人电话:12345671111<br/>
|
||
鉴于:<br/>
|
||
甲方系依法设立并合法存续的游戏公司,享有游戏《文本名称》(暂定名,以游戏在上线平台实际名称为准,以下简称“该游戏产品”)的全部著作权及发行、运营该游戏产品所需的所有商标权及其他合法权利,或已得到合法权利人的合法、完整、有效及可转授权的授权,拥有游戏产品的合法知识产权。拟对其游戏产品进行专业评估,以便向银行申请贷款等融资活动。<br/>
|
||
产权信息:<br/>
|
||
计算机软件著作权登记号:________________________;<br/>
|
||
资产编号:________________________;<br/>
|
||
游戏版号:________________________;<br/>
|
||
<br/>
|
||
乙方系一家具备合法资质、以游戏产业为主业的国有全资国家级科技型企业,以游戏数字资产管理、游戏发行运营、数字资产评估服务等为主要业务。拥有丰富的游戏行业评估经验和专业的评估团队,能够为甲方提供游戏产品评估服务并出具评估报告并上链。本评估报告经上链后,可溯源、不可篡改,作为可信数字资产应用参考有效依据。<br/>
|
||
甲乙双方经平等协商,在真实、充分地表达各自意愿的基础上,根据《中华人民共和国民法典》及相关法律法规的规定,就该游戏产品评估服务事宜达成如下协议,并由双方共同恪守:<br/>
|
||
第一条 服务内容<br/>
|
||
1.1 乙方接受甲方委托,为该游戏产品提供专业的评估服务,并出具《游戏产品评估报告》(以下简称“评估报告”)。<br/>
|
||
1.2 评估服务内容包括但不限于:游戏产品的市场价值分析、技术可行性评估、商业化潜力评估、游戏质量评估等专业评估内容。<br/>
|
||
1.3 评估报告将作为甲方向银行等金融机构申请贷款时的参考材料之一,乙方不对甲方能否成功获得贷款作出任何承诺或保证。<br/>
|
||
第二条 服务费用及支付方式<br/>
|
||
2.1 本次游戏产品评估服务费用为人民币壹仟元整(¥1,000.00元)。<br/>
|
||
2.2 甲方应通过乙方COG游戏可信资产服务平台提供的二维码支付方式完成服务费用的支付。<br/>
|
||
2.3 甲方完成扫码付费后,本协议即生效,乙方开始为甲方提供评估服务。<br/>
|
||
第三条 服务期限及交付<br/>
|
||
3.1 乙方应在甲方完成付费后的1个工作日内完成评估报告的编制工作。<br/>
|
||
3.2 评估报告完成后,甲方可通过乙方平台个人中心—游戏产品评估确权页面中进行下载。<br/>
|
||
3.3 如因甲方提供的游戏产品资料不完整、不准确或存在虚假陈述,导致评估工作无法正常进行或评估报告无法按时交付的,交付期限相应顺延,乙方不承担违约责任。<br/>
|
||
第四条 甲方的权利与义务<br/>
|
||
4.1 甲方有权要求乙方按照本协议约定提供评估服务,并按时获取评估报告。<br/>
|
||
4.2 甲方应向乙方提供评估所需的真实、完整、准确的游戏产品相关资料,包括但不限于游戏产品说明、技术文档、运营数据、知识产权证明等。<br/>
|
||
4.3 甲方应按照本协议约定及时支付服务费用。<br/>
|
||
4.4 甲方应对乙方提供的评估报告内容予以保密,未经乙方书面同意,不得将评估报告用于本协议约定以外的其他用途。<br/>
|
||
第五条 乙方的权利与义务<br/>
|
||
5.1 乙方有权按照本协议约定收取服务费用。<br/>
|
||
5.2 乙方应按照行业标准和专业规范,独立、客观、公正地为甲方提供评估服务,并出具评估报告。<br/>
|
||
5.3 乙方应对甲方提供的游戏产品资料及评估过程中知悉的甲方商业秘密予以保密,未经甲方书面同意,不得向任何第三方披露。<br/>
|
||
5.4 乙方应确保评估报告的内容真实,但评估报告中的结论和意见仅供银行参考,不构成对游戏产品价值的绝对保证。<br/>
|
||
第六条 知识产权<br/>
|
||
6.1 甲方提供的游戏产品及相关资料的知识产权归甲方所有。<br/>
|
||
6.2 乙方出具的评估报告的著作权归乙方所有,甲方获得该评估报告的使用权,使用范围限于向银行等金融机构申请贷款。<br/>
|
||
第七条 保密条款<br/>
|
||
7.1 双方应对在履行本协议过程中知悉的对方商业秘密、技术秘密及其他保密信息予以保密。<br/>
|
||
7.2 保密义务不因本协议的终止而失效,双方应持续承担保密义务。<br/>
|
||
7.3 如因一方违反保密义务给对方造成损失的,违约方应承担相应的赔偿责任。<br/>
|
||
第八条 协议的变更与终止<br/>
|
||
8.1 本协议的任何变更或补充,须经双方协商一致。<br/>
|
||
8.2 甲方申请退款后,本协议即行终止,乙方不再提供评估服务。<br/>
|
||
8.3 协议终止后,双方应按照本协议约定履行保密义务,已支付的款项将按原路退回。<br/>
|
||
第九条 违约责任<br/>
|
||
9.1 任何一方违反本协议约定的,应承担相应的违约责任,并赔偿由此给对方造成的直接经济损失。<br/>
|
||
9.2 因不可抗力导致本协议无法履行的,双方互不承担违约责任,但应及时通知对方并提供相关证明。<br/>
|
||
第十条 争议解决<br/>
|
||
10.1 本协议的订立、效力、解释、履行和争议解决均适用中华人民共和国法律。<br/>
|
||
10.2 因本协议引起的或与本协议有关的任何争议,双方应首先通过友好协商解决;协商不成的,任何一方均有权向乙方所在地有管辖权的人民法院提起诉讼。<br/>
|
||
第十一条 其他<br/>
|
||
11.1 本协议自甲方完成扫码付费之日起生效。<br/>
|
||
11.2 本协议一式两份,甲乙双方各执一份,具有同等法律效力。<br/>
|
||
11.3 本协议未尽事宜,双方可另行协商签订补充协议,补充协议与本协议具有同等法律效力。<br/>
|
||
<br/>
|
||
乙方(盖章):<br/>
|
||
授权代表(签字):<br/>
|
||
日期: 年 月 日 <br/>
|
||
<br/>
|
||
甲方授权代表(签字):<br/>
|
||
日期: 年 月 日<br/>
|
||
</div>
|
||
</div>
|
||
<div class="agreement-dialog-center">
|
||
<el-checkbox v-model="agreementChecked" class="agreement-checkbox-custom">
|
||
我已阅读并同意协议内容
|
||
</el-checkbox>
|
||
<span class="dialog-footer-center" slot="footer">
|
||
<el-button
|
||
class="agreement-sign-btn"
|
||
:disabled="!agreementChecked"
|
||
@click="onSignAgreement"
|
||
type="primary"
|
||
>同意协议并签字</el-button>
|
||
</span>
|
||
</div>
|
||
</el-dialog>
|
||
<!-- END 评估服务签约弹窗 -->
|
||
|
||
<!-- 优化后的签名弹窗 调用closeSignDialog-->
|
||
<el-dialog
|
||
:visible.sync="signDialogVisible"
|
||
width="70vh"
|
||
:close-on-click-modal="false"
|
||
:before-close="closeSignDialog"
|
||
top="170px"
|
||
custom-class="sign-dialog-custom"
|
||
>
|
||
<div class="sign-content">
|
||
<div class="sign-title-text">
|
||
请在下方进行签名:
|
||
</div>
|
||
<view class="signature-container signature-container-bg">
|
||
<canvas
|
||
canvas-id="signatureCanvas"
|
||
id="signatureCanvas"
|
||
class="signature-canvas"
|
||
:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px'}"
|
||
@mousedown="startDrawing"
|
||
@mousemove="draw"
|
||
@mouseup="stopDrawing"
|
||
@mouseleave="stopDrawing"
|
||
></canvas>
|
||
</view>
|
||
<div class="sign-tip-text">
|
||
请用鼠标在框内签署您的名字。
|
||
</div>
|
||
<view class="btn-group sign-btn-group">
|
||
<button @click="clearCanvas" class="sign-reset-btn">重置</button>
|
||
<button @click="saveSignature" class="sign-confirm-btn">确定</button>
|
||
</view>
|
||
</div>
|
||
</el-dialog>
|
||
<!-- END 优化后的签名弹窗 -->
|
||
|
||
<!-- 付费生产报告支付弹窗 -->
|
||
<el-dialog
|
||
:visible.sync="payDialogVisible"
|
||
width="70vh"
|
||
:close-on-click-modal="false"
|
||
custom-class="pay-dialog-custom"
|
||
>
|
||
<pay
|
||
v-if="payDialogVisible"
|
||
:order-id="payRow"
|
||
@pay-success="onPaySuccess"
|
||
@close="payDialogVisible = false"
|
||
/>
|
||
</el-dialog>
|
||
<!-- END 付费生产报告支付弹窗 -->
|
||
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</Layout>
|
||
</template>
|
||
|
||
<script>
|
||
import Layout from './part/layouts.vue';
|
||
import memberleft from './part/member_left.vue';
|
||
import pay from './part/pay.vue';
|
||
|
||
export default {
|
||
components: {
|
||
Layout,
|
||
memberleft,
|
||
pay,
|
||
},
|
||
data() {
|
||
return {
|
||
page: 1,
|
||
list_rows: 10,
|
||
listData: [],
|
||
total: 0,
|
||
name: '',
|
||
agreementDialogVisible: false,
|
||
agreementChecked: true, // 默认勾选
|
||
agreementRow: null, // 签约操作的那行数据
|
||
signDialogVisible: false, // 控制签字弹窗
|
||
// 签名相关
|
||
canvasWidth: 510, // 优化宽度为与弹窗合适的比例
|
||
canvasHeight: 350, // 优化高度为合适的签字区域
|
||
ctx: null,
|
||
isDrawing: false,
|
||
lastX: 0,
|
||
lastY: 0,
|
||
signatureBase64: '',
|
||
payDialogVisible: false, // 支付弹框
|
||
payRow: null, // 付费弹框记录的当前行数据
|
||
};
|
||
},
|
||
created() {
|
||
let obj = this.$Route ? this.$Route.query : (this.$route ? this.$route.query : {});
|
||
if (obj && obj.hasOwnProperty('index')) {
|
||
this.category_id = Number(obj.index);
|
||
}
|
||
},
|
||
mounted() {
|
||
this.initCanvas();
|
||
},
|
||
onShow() {
|
||
this.getData();
|
||
},
|
||
watch: {
|
||
signDialogVisible(val) {
|
||
if(val) {
|
||
this.$nextTick(() => {
|
||
this.initCanvas();
|
||
});
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
downloadPDF(e) {
|
||
if (!e) {
|
||
this.$message.error('评估报告生成中~');
|
||
} else {
|
||
window.open(e, '_blank');
|
||
}
|
||
},
|
||
goEdit(e) {
|
||
if (uni.getStorageSync('apply_status') == 3) {
|
||
this.$message.error('用户认证审核中');
|
||
return false;
|
||
}
|
||
if (uni.getStorageSync('apply_status') == 2) {
|
||
this.$message.error('用户认证失败,请重新提交审核');
|
||
return false;
|
||
}
|
||
this.$router.push({
|
||
path: 'asset_add',
|
||
query: {
|
||
id: e,
|
||
},
|
||
});
|
||
},
|
||
finds(e) {
|
||
uni.showModal({
|
||
title: '审核意见',
|
||
content: e.auth_remark ? e.auth_remark : '无审核意见说明',
|
||
showCancel: true,
|
||
cancelText: '取消',
|
||
cancelColor: '#cccccc',
|
||
confirmText: '确定',
|
||
confirmColor: '#F78A30',
|
||
success: function (res) {
|
||
if (res.confirm) {
|
||
} else if (res.cancel) {
|
||
console.log('用户点击取消');
|
||
}
|
||
},
|
||
fail: function (err) {
|
||
console.log('调用失败:', err);
|
||
},
|
||
complete: function () {},
|
||
});
|
||
},
|
||
findqy(e) {
|
||
uni.showModal({
|
||
title: '签约审核意见',
|
||
content: e.contract_audit_remark ? e.contract_audit_remark : '无审核意见说明',
|
||
showCancel: true,
|
||
cancelText: '取消',
|
||
cancelColor: '#cccccc',
|
||
confirmText: '确定',
|
||
confirmColor: '#F78A30',
|
||
success: function (res) {
|
||
if (res.confirm) {
|
||
} else if (res.cancel) {
|
||
console.log('用户点击取消');
|
||
}
|
||
},
|
||
fail: function (err) {
|
||
console.log('调用失败:', err);
|
||
},
|
||
complete: function () {},
|
||
});
|
||
},
|
||
|
||
asset_add() {
|
||
if (uni.getStorageSync('apply_status') == 3) {
|
||
this.$message.error('用户认证审核中');
|
||
return false;
|
||
}
|
||
if (uni.getStorageSync('apply_status') == 2) {
|
||
this.$message.error('用户认证失败,请重新提交审核');
|
||
return false;
|
||
}
|
||
if (uni.getStorageSync('third_auth_status') == 0) {
|
||
this.$message.error('请提交实名认证');
|
||
return false;
|
||
}
|
||
if (uni.getStorageSync('third_auth_status') == 2) {
|
||
this.$message.error('未注册天府信用通账号,请联系管理员');
|
||
return false;
|
||
}
|
||
uni.navigateTo({
|
||
url: '/asset_add',
|
||
});
|
||
},
|
||
handleSizeChange(val) {
|
||
this.list_rows = val;
|
||
this.getData();
|
||
},
|
||
handleCurrentChange(val) {
|
||
this.page = val;
|
||
this.getData();
|
||
},
|
||
getData() {
|
||
this._get(
|
||
'asset.asset/index',
|
||
{
|
||
page: this.page,
|
||
limit: this.list_rows,
|
||
name: this.name,
|
||
},
|
||
(res) => {
|
||
this.listData = res.data.data;
|
||
this.total = res.data.total;
|
||
},
|
||
(err) => {
|
||
uni.showToast({
|
||
icon: 'none',
|
||
title: err.data.msg,
|
||
});
|
||
return;
|
||
}
|
||
);
|
||
},
|
||
openAgreementDialog(row) {
|
||
this.agreementDialogVisible = true;
|
||
this.agreementChecked = true; // 默认勾选
|
||
this.agreementRow = row; // 存下需要签约的那一行数据
|
||
},
|
||
onSignAgreement() {
|
||
this.signDialogVisible = true;
|
||
this.agreementDialogVisible = false; // 保持true,协议弹窗通过v-if隐藏
|
||
},
|
||
//关闭弹窗清除签名
|
||
closeSignDialog() {
|
||
this.signDialogVisible = false;
|
||
this.clearCanvas();
|
||
},
|
||
// ------- 新版签名逻辑:完全参考参考代码 -------
|
||
initCanvas() {
|
||
this.$nextTick(() => {
|
||
this.ctx = uni.createCanvasContext('signatureCanvas', this);
|
||
// 设置画笔样式
|
||
this.ctx.setStrokeStyle('#000000');
|
||
this.ctx.setLineWidth(3);
|
||
this.ctx.setLineCap('round');
|
||
this.ctx.setLineJoin('round');
|
||
});
|
||
},
|
||
|
||
// 鼠标按下,开始绘制
|
||
startDrawing(e) {
|
||
this.isDrawing = true;
|
||
this.getRectAndCoords(e, (x, y) => {
|
||
this.lastX = x;
|
||
this.lastY = y;
|
||
this.ctx.beginPath();
|
||
this.ctx.moveTo(x, y);
|
||
this.ctx.stroke();
|
||
this.ctx.draw(true);
|
||
});
|
||
},
|
||
|
||
// 鼠标移动,连续绘制线条
|
||
draw(e) {
|
||
if (!this.isDrawing) return;
|
||
this.getRectAndCoords(e, (x, y) => {
|
||
this.ctx.beginPath();
|
||
this.ctx.moveTo(this.lastX, this.lastY);
|
||
this.ctx.lineTo(x, y);
|
||
this.ctx.stroke();
|
||
this.ctx.draw(true);
|
||
this.lastX = x;
|
||
this.lastY = y;
|
||
});
|
||
},
|
||
|
||
// 鼠标松开
|
||
stopDrawing() {
|
||
this.isDrawing = false;
|
||
},
|
||
|
||
// 统一坐标转换
|
||
getRectAndCoords(e, cb) {
|
||
const query = uni.createSelectorQuery().in(this);
|
||
query
|
||
.select('#signatureCanvas')
|
||
.boundingClientRect((rect) => {
|
||
let x = 0, y = 0;
|
||
if (e.pageX !== undefined && e.pageY !== undefined) {
|
||
x = e.pageX - rect.left;
|
||
y = e.pageY - rect.top;
|
||
} else if (e.touches && e.touches.length) {
|
||
x = e.touches[0].pageX - rect.left;
|
||
y = e.touches[0].pageY - rect.top;
|
||
} else if ('clientX' in e && 'clientY' in e) {
|
||
x = e.clientX - rect.left;
|
||
y = e.clientY - rect.top;
|
||
}
|
||
cb(x, y);
|
||
})
|
||
.exec();
|
||
},
|
||
|
||
clearCanvas() {
|
||
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
|
||
this.ctx.draw();
|
||
},
|
||
|
||
saveSignature() {
|
||
const _this = this;
|
||
uni.canvasToTempFilePath({
|
||
x: 0,
|
||
y: 0,
|
||
width: this.canvasWidth,
|
||
height: this.canvasHeight,
|
||
canvasId: 'signatureCanvas',
|
||
success: function (res) {
|
||
_this.getBase64FromCanvas();
|
||
},
|
||
fail: function (err) {
|
||
console.error('保存失败', err);
|
||
},
|
||
}, this);
|
||
},
|
||
|
||
getBase64FromCanvas() {
|
||
const _this = this;
|
||
const query = uni.createSelectorQuery().in(this);
|
||
query
|
||
.select('#signatureCanvas')
|
||
.fields({ node: true, size: true })
|
||
.exec((res) => {
|
||
if (res[0] && res[0].node && typeof res[0].node.toDataURL === 'function') {
|
||
const canvas = res[0].node;
|
||
const base64 = canvas.toDataURL('image/png');
|
||
_this.signatureBase64 = base64;
|
||
_this.uploadToBackend(base64);
|
||
} else {
|
||
uni.canvasToTempFilePath({
|
||
canvasId: 'signatureCanvas',
|
||
success: (ret) => {
|
||
if (window && window.FileReader) {
|
||
fetch(ret.tempFilePath)
|
||
.then(res => res.blob())
|
||
.then(blob => {
|
||
const reader = new FileReader();
|
||
reader.onload = (event) => {
|
||
_this.signatureBase64 = event.target.result;
|
||
_this.uploadToBackend(event.target.result);
|
||
};
|
||
reader.readAsDataURL(blob);
|
||
});
|
||
} else {
|
||
_this.uploadToBackend(ret.tempFilePath);
|
||
}
|
||
},
|
||
}, _this);
|
||
}
|
||
});
|
||
},
|
||
|
||
// 优化签名图片上传:将base64转为Blob后上传,更兼容后端图片处理
|
||
uploadToBackend(base64Data) {
|
||
const that = this;
|
||
let filetype = "image";
|
||
|
||
// 将base64字符串转换为Blob对象
|
||
function dataURLtoBlob(dataurl) {
|
||
let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
|
||
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
|
||
while(n--){
|
||
u8arr[n] = bstr.charCodeAt(n);
|
||
}
|
||
return new Blob([u8arr], {type:mime});
|
||
}
|
||
|
||
const blob = dataURLtoBlob(base64Data);
|
||
const formData = new FormData();
|
||
// 文件名可自定义,image.png
|
||
formData.append('iFile', blob, 'signature.png');
|
||
formData.append('type', filetype);
|
||
formData.append('app_id', '10001');
|
||
formData.append('token', uni.getStorageSync('token') || '');
|
||
// uni.request暂不支持直接传formData,改用原生XMLHttpRequest优化图片上传
|
||
const xhr = new XMLHttpRequest();
|
||
xhr.open('POST', this.config.app_url+'/api/file.upload/file', true);
|
||
xhr.onreadystatechange = function () {
|
||
if (xhr.readyState === 4) {
|
||
if (xhr.status === 200) {
|
||
let res;
|
||
try {
|
||
res = JSON.parse(xhr.responseText);
|
||
} catch (e) {
|
||
that.$message.error('签名上传返回异常');
|
||
return;
|
||
}
|
||
console.log(res.data.file_id,2222222222222222)
|
||
if(res.code === 1){
|
||
// 调用签约接口给后端参数
|
||
that.toqy(res.data.file_id);
|
||
|
||
} else {
|
||
that.$message.error(res.msg || '上传失败');
|
||
}
|
||
} else {
|
||
that.$message.error('上传失败');
|
||
}
|
||
}
|
||
};
|
||
xhr.onerror = function () {
|
||
that.$message.error('网络错误');
|
||
};
|
||
xhr.send(formData);
|
||
},
|
||
|
||
|
||
toqy(e) {
|
||
this._post('/asset.Asset/sign', {
|
||
signature_file_id: e,
|
||
id: this.agreementRow.id,
|
||
}, res => {
|
||
this.$message.success('签约提交成功!');
|
||
this.signDialogVisible = false;
|
||
this.agreementDialogVisible = false;
|
||
this.getData();
|
||
}, err => {
|
||
uni.showToast({
|
||
icon: 'none',
|
||
title: err.data.msg
|
||
})
|
||
return;
|
||
});
|
||
},
|
||
openPayDialog(row) {
|
||
this.payDialogVisible = true;
|
||
this.payRow = row.id;
|
||
},
|
||
onPaySuccess() {
|
||
this.payDialogVisible = false;
|
||
this.getData();
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.bg{
|
||
width: 100%;
|
||
background: #F1F1F1;
|
||
min-height: 800px;
|
||
}
|
||
.content{
|
||
width: 1290px;
|
||
margin: 0 auto;
|
||
padding-top: 14px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
.content_left{
|
||
width: 245px;
|
||
min-height: 789px;
|
||
background: #FFFFFF;
|
||
box-shadow: 0px 4px 10px 0px rgba(78,89,105,0.06);
|
||
border-radius: 0px 0px 0px 0px;
|
||
}
|
||
.content_right{
|
||
width: 1024px;
|
||
min-height: 789px;
|
||
background: #FFFFFF;
|
||
box-shadow: 0px 4px 10px 0px rgba(78,89,105,0.06);
|
||
border-radius: 0px 0px 0px 0px;
|
||
}
|
||
.mtitle{
|
||
font-weight: 500;
|
||
font-size: 16px;
|
||
color: #3D3D3D;
|
||
width: 985px;
|
||
margin:0 auto;
|
||
height: 48px;
|
||
line-height: 48px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.lines{
|
||
width: 985px;
|
||
height: 0px;
|
||
border: 1px solid #D8D8D8;
|
||
opacity: 0.6;
|
||
margin:0 auto;
|
||
}
|
||
.mimg{
|
||
width: 20px;
|
||
height: 20px;
|
||
margin-right: 10px;
|
||
margin-left: 23px;
|
||
}
|
||
.content_r{
|
||
padding: 34px 22px;
|
||
}
|
||
.addimg{
|
||
width: 12px;
|
||
height: 12px;
|
||
margin-left: 5px;
|
||
}
|
||
.addimgs{
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-left: 8px;
|
||
}
|
||
.adds{
|
||
width: 80px;
|
||
height: 32px;
|
||
background: #F78A30;
|
||
border-radius: 4px 4px 4px 4px;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #FFFFFF;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
}
|
||
.search-box{
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
width: 358px;
|
||
}
|
||
.search-name{
|
||
width: 232px;
|
||
height: 32px;
|
||
background: #F7F8FA;
|
||
padding: 0 12px;
|
||
font-size: 14px;
|
||
color: #333333;
|
||
line-height: 32px;
|
||
}
|
||
.search-names{
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #86909C;
|
||
}
|
||
.qqtable{
|
||
margin-top: 30px;
|
||
}
|
||
::v-deep .el-table__header th {
|
||
background-color: #F2F3F5;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #1D2129;
|
||
text-align: center;
|
||
}
|
||
.green{
|
||
font-weight: 400;
|
||
font-size: 12px;
|
||
color: #20BC30;
|
||
}
|
||
.red{
|
||
font-weight: 400;
|
||
font-size: 12px;
|
||
color: #EA3B3B;
|
||
}
|
||
.center-table .el-table__header th,
|
||
.center-table .el-table__body td {
|
||
color: #EA3B3B !important;
|
||
}
|
||
.asset_e{
|
||
font-weight: 400;
|
||
font-size: 12px;
|
||
color: #F6773C;
|
||
}
|
||
.asset_l{
|
||
font-weight: 400;
|
||
font-size: 12px;
|
||
color: #165DFF;
|
||
}
|
||
::v-deep .el-table__fixed-right::before, .el-table__fixed::before{
|
||
background-color:#ffffff !important;
|
||
}
|
||
|
||
.asset_list_desc{
|
||
width: 908px;
|
||
height: 72px;
|
||
background: rgba(255,247,241,0.6);
|
||
border-radius: 8px 8px 8px 8px;
|
||
border: 1px solid #F78A30;
|
||
margin: 24px auto;
|
||
padding: 24px;
|
||
}
|
||
.assetDesc{
|
||
display: flex;
|
||
align-items: center;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #3D3D3D;
|
||
line-height: 24px;
|
||
text-align: left;
|
||
}
|
||
.assetDesc_dian{
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 100%;
|
||
background-color: #3D3D3D;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.agreement-content {
|
||
white-space: pre-wrap;
|
||
}
|
||
|
||
.agreement-dialog-custom {
|
||
width: 657px !important;
|
||
height: 738px !important;
|
||
background: #FFFFFF !important;
|
||
box-shadow: 0px 4px 10px 0px rgba(0,0,0,0.2) !important;
|
||
border-radius: 8px !important;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-start;
|
||
align-items: center;
|
||
padding: 0 !important;
|
||
}
|
||
.agreement-dialog-header {
|
||
width: 100%;
|
||
text-align: center;
|
||
margin-top: -35px;
|
||
}
|
||
.agreement-dialog-title {
|
||
letter-spacing: 1px;
|
||
font-family: Source Han Sans, Source Han Sans;
|
||
font-weight: 500;
|
||
font-size: 18px;
|
||
color: #3D3D3D;
|
||
}
|
||
.agreement-content {
|
||
white-space: pre-wrap;
|
||
padding: 0 42px;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
.agreement-dialog-center {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin-top: 20px;
|
||
}
|
||
.agreement-checkbox-custom {
|
||
margin-top: 18px !important;
|
||
display: flex;
|
||
justify-content: center;
|
||
width: 220px;
|
||
--el-checkbox-checked-icon-color: #F78A30;
|
||
--el-checkbox-checked-bg-color: #F78A30;
|
||
}
|
||
::v-deep .el-checkbox__input.is-checked .el-checkbox__inner {
|
||
background-color: #F78A30 !important;
|
||
border-color: #F78A30 !important;
|
||
}
|
||
.dialog-footer-center {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin-top: 20px;
|
||
}
|
||
.agreement-sign-btn {
|
||
width: 236px !important;
|
||
height: 46px !important;
|
||
background: #F78A30 !important;
|
||
border: none !important;
|
||
color: #fff !important;
|
||
font-size: 16px;
|
||
border-radius: 4px !important;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: background 0.2s;
|
||
}
|
||
.agreement-sign-btn[disabled], .agreement-sign-btn.is-disabled {
|
||
background: #FFDEC4 !important;
|
||
color: #fff !important;
|
||
cursor: not-allowed !important;
|
||
}
|
||
::v-deep .el-checkbox__input.is-checked+.el-checkbox__label , ::v-deep .el-checkbox__label
|
||
{
|
||
color: #3d3d3d !important;
|
||
font-size: 14px !important;
|
||
margin-top: -2px !important;
|
||
}
|
||
.sign-dialog-custom {
|
||
width: 730px !important;
|
||
height: 660px !important;
|
||
background: #FFFFFF !important;
|
||
box-shadow: 0px 4px 10px 0px rgba(0,0,0,0.2) !important;
|
||
border-radius: 8px !important;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
padding: 0 !important;
|
||
}
|
||
.sign-content {
|
||
flex: 1;
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
box-sizing: border-box;
|
||
padding-bottom: 30px;
|
||
}
|
||
|
||
.sign-title-text {
|
||
color: #333;
|
||
font-size: 15px;
|
||
margin-bottom: 20px;
|
||
margin-top: 0;
|
||
}
|
||
|
||
.signature-container {
|
||
width: 510px;
|
||
height: 300px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 10px;
|
||
border: 1px solid #B5D4EB;
|
||
overflow: hidden;
|
||
box-sizing: border-box;
|
||
margin-bottom: 12px;
|
||
max-width: 98vw;
|
||
max-height: 60vh;
|
||
}
|
||
.signature-container-bg {
|
||
background: #F0F9FF;
|
||
}
|
||
|
||
.signature-canvas {
|
||
display: block;
|
||
margin: 0 auto;
|
||
background: transparent;
|
||
}
|
||
|
||
.sign-tip-text {
|
||
font-size: 12px;
|
||
color: #999;
|
||
margin-top: 3px;
|
||
text-align: center;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.sign-btn-group {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin-top: 26px;
|
||
gap: 16px;
|
||
}
|
||
|
||
.sign-reset-btn {
|
||
width: 100px;
|
||
height: 38px;
|
||
border-radius: 4px;
|
||
border: 1px solid #F78A30;
|
||
background: #fff;
|
||
color: #F78A30;
|
||
font-size: 14px;
|
||
}
|
||
.sign-confirm-btn {
|
||
width: 100px;
|
||
height: 38px;
|
||
border-radius: 4px;
|
||
background: #F78A30 !important;
|
||
color: #fff !important;
|
||
font-size: 15px;
|
||
border: none !important;
|
||
}
|
||
|
||
.pay-dialog-custom {
|
||
width: 480px !important;
|
||
background: #fff !important;
|
||
border-radius: 10px !important;
|
||
box-shadow: 0px 4px 10px 0px rgba(0,0,0,0.18) !important;
|
||
}
|
||
|
||
@media screen and (max-width: 950px) {
|
||
.sign-dialog-custom {
|
||
width: 98vw !important;
|
||
height: 98vh !important;
|
||
}
|
||
.signature-container {
|
||
width: 96vw !important;
|
||
max-width: 98vw !important;
|
||
height: 48vw !important;
|
||
max-height: 90vw !important;
|
||
}
|
||
}
|
||
@media screen and (max-width: 768px) {
|
||
.agreement-dialog-custom {
|
||
width: 99vw !important;
|
||
height: 98vh !important;
|
||
padding: 0 !important;
|
||
}
|
||
.sign-dialog-custom {
|
||
width: 99vw !important;
|
||
height: 98vh !important;
|
||
}
|
||
.signature-container {
|
||
width: 95vw !important;
|
||
max-width: 98vw !important;
|
||
height: 34vw !important;
|
||
max-height: 56vw !important;
|
||
}
|
||
.pay-dialog-custom {
|
||
width: 99vw !important;
|
||
}
|
||
}
|
||
</style>
|