feat: 新增AI客服/积分管理/合同审查/我的报告页面,完善.sign.vue入口与积分显示

This commit is contained in:
2026-10-16 21:09:21 +08:00
parent 8a1da677e4
commit ae97c5d2be
476 changed files with 35618 additions and 540 deletions
+1
View File
@@ -1,2 +1,3 @@
/node_modules/ /node_modules/
**/node_modules/
/unpackage/ /unpackage/
+1
View File
@@ -0,0 +1 @@
shamefully-hoist=true
+6151
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -31,6 +31,7 @@
"js-md5": "^0.8.3", "js-md5": "^0.8.3",
"mp-html": "^2.5.1", "mp-html": "^2.5.1",
"normalize-wheel": "^1.0.1", "normalize-wheel": "^1.0.1",
"pdfh5": "^2.0.6",
"pdfjs-dist": "2.5.207", "pdfjs-dist": "2.5.207",
"request": "^2.88.2", "request": "^2.88.2",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
+28
View File
@@ -441,6 +441,34 @@
"navigationBarTitleText": "文章列表", "navigationBarTitleText": "文章列表",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
},
{
"path": "pages/ai/chat",
"style": {
"navigationBarTitleText": "AI客服",
"navigationStyle": "custom"
}
},
{
"path": "pages/ai/points",
"style": {
"navigationBarTitleText": "积分管理",
"navigationStyle": "custom"
}
},
{
"path": "pages/ai/review",
"style": {
"navigationBarTitleText": "合同审查",
"navigationStyle": "custom"
}
},
{
"path": "pages/ai/reports",
"style": {
"navigationBarTitleText": "我的报告",
"navigationStyle": "custom"
}
} }
], ],
"globalStyle": { "globalStyle": {
+235
View File
@@ -0,0 +1,235 @@
<template>
<view class="chat-wrap">
<!-- 顶部导航 -->
<uititle title="AI 智能客服"></uititle>
<!-- 消息列表 -->
<scroll-view scroll-y class="msg-list" :scroll-into-view="scrollId" scroll-with-animation
:style="{ height: msgListHeight + 'px' }">
<!-- 欢迎消息 -->
<view v-if="messages.length === 0" class="msg-item left" id="msg-welcome">
<view class="avatar">🤖</view>
<view class="bubble">
您好!我是金久信签约宝AI智能客服,可以帮您解答金久信签约宝使用过程中注册、操作、适用场景等问题。请问有什么可以帮您?
<view class="quick-btns">
<view class="quick-btn" @click="quickSend('注册准备资料事项')">注册准备资料事项</view>
<view class="quick-btn" @click="quickSend('关键字无法识别')">关键字无法识别</view>
<view class="quick-btn" @click="quickSend('金久信签约宝法律效力')">金久信签约宝法律效力</view>
<view class="quick-btn" @click="quickSend('电子签约不适用场景')">电子签约不适用场景</view>
</view>
</view>
</view>
<!-- 对话消息 -->
<view v-for="(msg, i) in messages" :key="i" :id="'msg' + i"
:class="['msg-item', msg.role === 'user' ? 'right' : 'left']">
<view v-if="msg.role !== 'user'" class="avatar">🤖</view>
<view class="bubble" v-html="formatContent(msg.content)"></view>
</view>
<!-- 加载中 -->
<view v-if="loading" class="msg-item left" id="msg-loading">
<view class="avatar">🤖</view>
<view class="bubble loading">思考中...</view>
</view>
</scroll-view>
<!-- 底部输入栏 -->
<view class="input-bar">
<input v-model="inputText" @confirm="send" placeholder="输入您的问题..."
:adjust-position="true" confirm-type="send" />
<view class="send-btn" @click="send">发送</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
inputText: '',
messages: [],
loading: false,
conversationId: null,
scrollId: '',
msgListHeight: 500
};
},
onReady() {
// 计算消息列表高度(屏幕高度 - 导航栏 - 输入栏)
const sys = uni.getSystemInfoSync();
this.msgListHeight = sys.windowHeight - 88 - 56;
},
methods: {
formatContent(text) {
if (!text) return '';
let html = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
html = html.replace(/^[\-\•]\s+(.+)$/gm, '<div style="padding-left:12px;">• $1</div>');
html = html.replace(/^(\d+)\.\s+(.+)$/gm, '<div style="padding-left:12px;">$1. $2</div>');
html = html.replace(/\n/g, '<br>');
return html;
},
quickSend(text) {
this.inputText = text;
this.send();
},
async send() {
const msg = this.inputText.trim();
if (!msg || this.loading) return;
this.inputText = '';
this.messages.push({ role: 'user', content: msg });
this.loading = true;
this.scrollToBottom();
try {
const res = await this.vk.callFunction({
url: 'client/ai/pub/chat',
data: { message: msg, bot_id: '7683509749475819554' }
});
if (res.data.conversation_id) this.conversationId = res.data.conversation_id;
this.messages.push({ role: 'assistant', content: res.data.answer });
} catch (e) {
this.messages.push({ role: 'assistant', content: '网络异常,请稍后重试' });
}
this.loading = false;
this.scrollToBottom();
},
scrollToBottom() {
this.$nextTick(() => {
setTimeout(() => {
if (this.messages.length === 0) {
this.scrollId = 'msg-welcome';
} else if (this.loading) {
this.scrollId = 'msg-loading';
} else {
this.scrollId = 'msg' + (this.messages.length - 1);
}
}, 50);
});
}
}
};
</script>
<style lang="scss" scoped>
.chat-wrap {
height: 93vh;
display: flex;
flex-direction: column;
background: #f5f5f5;
}
uni-scroll-view{
width: auto !important;
}
.msg-list {
flex: 1;
padding-left: 24rpx;
padding-right: 24rpx;
padding-top :24rpx;
}
.msg-item {
display: flex;
margin-bottom: 24rpx;
align-items: flex-start;
}
.msg-item.right {
flex-direction: row-reverse;
}
.avatar {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: linear-gradient(135deg, #a92924, #d4574e);
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
flex-shrink: 0;
}
.bubble {
max-width: 70%;
padding: 20rpx 24rpx;
border-radius: 24rpx;
font-size: 28rpx;
line-height: 1.6;
word-break: break-word;
}
.msg-item.left .bubble {
background: #fff;
color: #333;
margin-left: 16rpx;
border-top-left-radius: 8rpx;
}
.msg-item.right .bubble {
background: #a92924;
color: #fff;
margin-right: 16rpx;
border-top-right-radius: 8rpx;
}
.bubble.loading {
color: #999;
}
.quick-btns {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
margin-top: 16rpx;
}
.quick-btn {
padding: 8rpx 24rpx;
border-radius: 28rpx;
font-size: 24rpx;
border: 1px solid #a92924;
color: #a92924;
background: #fff;
}
.quick-btn:active {
background: #a92924;
color: #fff;
}
.input-bar {
display: flex;
align-items: center;
padding: 16rpx 24rpx;
background: #fff;
border-top: 1px solid #eee;
gap: 16rpx;
}
.input-bar input {
flex: 1;
height: 72rpx;
background: #f5f5f5;
border-radius: 36rpx;
padding: 0 24rpx;
font-size: 28rpx;
}
.send-btn {
width: 120rpx;
height: 72rpx;
line-height: 72rpx;
text-align: center;
background: #a92924;
color: #fff;
border-radius: 36rpx;
font-size: 28rpx;
flex-shrink: 0;
}
.send-btn:active {
background: #982520;
}
</style>
+243
View File
@@ -0,0 +1,243 @@
<template>
<view class="page-wrap">
<uititle title="积分管理"></uititle>
<!-- 积分概览 -->
<view class="points-header">
<view class="ph-card main">
<view class="ph-label">可用积分</view>
<view class="ph-value">{{ pointsBalance }}</view>
</view>
<view class="ph-card sub">
<view class="ph-label">累计获得</view>
<view class="ph-value">{{ pointsTotalEarned }}</view>
</view>
</view>
<!-- 充值套餐 -->
<view class="section-title">💎 积分充值</view>
<view class="recharge-grid">
<view v-for="(pkg, i) in rechargePackages" :key="i"
:class="['recharge-card', selectedRecharge === i && 'selected']"
@click="selectedRecharge = i">
<view class="rc-points">{{ pkg.points }}</view>
<view class="rc-price">{{ pkg.price }}</view>
<view v-if="pkg.bonus" class="rc-bonus">{{ pkg.bonus }}</view>
</view>
</view>
<view class="p-20">
<u-button type="primary" shape="circle" @click="doRecharge">
立即充值 {{ rechargePackages[selectedRecharge].price }}({{ rechargePackages[selectedRecharge].points }} 积分)
</u-button>
</view>
<!-- 积分明细 -->
<view class="section-title">📊 积分明细</view>
<view v-if="pointsLogList.length === 0" class="empty-tip">暂无积分记录</view>
<view v-for="(item, i) in pointsLogList" :key="i" class="log-item">
<view class="log-left">
<view class="log-reason">{{ item.reason }}</view>
<view class="log-time">{{ item._add_time_str }}</view>
</view>
<view :class="['log-amount', item.type === 'earn' ? 'green' : 'red']">
{{ item.type === 'earn' ? '+' : '-' }}{{ Math.abs(item.amount) }}
</view>
</view>
</view>
</template>
<script>
import uititle from '@/components/common/title'
import dayjs from 'dayjs'
export default {
components: { uititle },
data() {
return {
pointsBalance: 0,
pointsTotalEarned: 0,
pointsLogList: [],
selectedRecharge: 1,
rechargePackages: [
{ points: 10000, price: '20元', bonus: '' },
{ points: 50000, price: '100元', bonus: '' },
{ points: 100000, price: '200元', bonus: '' },
{ points: 450000, price: '900元', bonus: '' },
{ points: 1000000, price: '2000元', bonus: '' },
{ points: 2000000, price: '4000元', bonus: '' },
]
}
},
onShow() {
this.getPointsBalance()
this.getPointsLog()
},
methods: {
async getPointsBalance() {
const res = await vk.callFunction({ url: 'client/points/kh/getBalance' })
if (res.code === 0 && res.data) {
this.pointsBalance = res.data.balance || 0
this.pointsTotalEarned = res.data.total_earned || 0
}
},
async getPointsLog() {
const res = await vk.callFunction({
url: 'client/points/kh/getLog',
data: { pageIndex: 1, pageSize: 50 }
})
if (res.code === 0 && res.data) {
this.pointsLogList = (res.data.rows || []).map(r => ({
...r,
_add_time_str: dayjs(r._add_time && r._add_time['$date'] ? r._add_time['$date'] : r._add_time).format('YYYY-MM-DD HH:mm')
}))
}
},
async doRecharge() {
const pkg = this.rechargePackages[this.selectedRecharge]
const priceMap = {
'20元': 2000, '100元': 10000, '200元': 20000,
'900元': 90000, '2000元': 200000, '4000元': 400000
}
const price = priceMap[pkg.price] || 2000
const res = await vk.callFunction({
url: 'client/points/kh/createOrder',
data: { points: pkg.points, price }
})
if (res.code === 0 && res.data) {
uni.navigateTo({ url: '/pages/shop/pay?id=' + res.data })
} else {
uni.showToast({ title: res.msg || '创建订单失败', icon: 'none' })
}
}
}
}
</script>
<style lang="scss" scoped>
.page-wrap {
min-height: 100vh;
background: #f5f5f5;
}
.points-header {
display: flex;
gap: 20rpx;
padding: 30rpx;
}
.ph-card {
flex: 1;
padding: 30rpx;
border-radius: 16rpx;
color: #fff;
text-align: center;
}
.ph-card.main {
background: linear-gradient(135deg, #a92924, #d4574e);
}
.ph-card.sub {
background: linear-gradient(135deg, #333, #666);
}
.ph-label {
font-size: 24rpx;
opacity: 0.85;
}
.ph-value {
font-size: 48rpx;
font-weight: 700;
margin-top: 8rpx;
}
.section-title {
font-size: 30rpx;
font-weight: 600;
padding: 20rpx 30rpx 10rpx;
}
.recharge-grid {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
padding: 0 30rpx;
}
.recharge-card {
flex: 0 0 calc(33.33% - 12rpx);
padding: 24rpx 0;
text-align: center;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
background: #fff;
position: relative;
}
.recharge-card.selected {
border-color: #a92924;
background: #fdf0f0;
}
.rc-points {
font-size: 32rpx;
font-weight: 700;
color: #333;
}
.rc-price {
font-size: 24rpx;
color: #999;
margin-top: 4rpx;
}
.rc-bonus {
position: absolute;
top: -2rpx;
right: -2rpx;
background: #a92924;
color: #fff;
font-size: 18rpx;
padding: 2rpx 10rpx;
border-radius: 0 10rpx 0 10rpx;
}
.log-item {
display: flex;
align-items: center;
padding: 24rpx 30rpx;
background: #fff;
border-bottom: 1rpx solid #f0f0f0;
}
.log-left {
flex: 1;
}
.log-reason {
font-size: 28rpx;
color: #333;
}
.log-time {
font-size: 22rpx;
color: #999;
margin-top: 4rpx;
}
.log-amount {
font-size: 32rpx;
font-weight: 600;
}
.log-amount.green { color: #67c23a; }
.log-amount.red { color: #f56c6c; }
.empty-tip {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 26rpx;
}
</style>
+264
View File
@@ -0,0 +1,264 @@
<template>
<view class="page-wrap">
<uititle title="我的报告"></uititle>
<!-- 查询按钮 -->
<view class="action-bar">
<u-button type="primary" size="small" shape="circle" @click="queryReports">
🔍 查询报告
</u-button>
</view>
<!-- 空状态 -->
<view v-if="reportList.length === 0 && !loading" class="empty-box">
<view class="empty-icon">📋</view>
<view class="empty-text">暂无审查报告</view>
<view class="empty-hint">点击上方「查询报告」从服务器加载</view>
</view>
<!-- 加载中 -->
<view v-if="loading" class="loading-box">
<u-loading-icon size="48"></u-loading-icon>
<text class="loading-text">加载中...</text>
</view>
<!-- 报告列表 -->
<view v-for="(r, i) in reportList" :key="i" class="report-item">
<view class="report-header">
<view class="report-name">📄 {{ r.fileName }}</view>
<view :class="['status-tag', 'status-' + r.status]">{{ statusMap[r.status] || r.status }}</view>
</view>
<view class="report-meta">{{ r.time }} · 消耗 {{ r.amount }} 积分</view>
<view class="report-actions">
<view v-if="r.htmlUrl" class="action-btn" @click="openUrl(r.htmlUrl)">📄 查看报告</view>
<view v-if="r.fileUrl" class="action-btn" @click="openUrl(r.fileUrl)">📎 查看文件</view>
<view v-if="r.status === 'completed' && r.result" class="action-btn" @click="viewSummary(r)">📋 查看摘要</view>
</view>
</view>
<!-- 摘要弹窗 -->
<u-popup :show="showSummary" mode="bottom" @close="showSummary = false" round="24">
<view class="summary-popup">
<view class="summary-title">📋 审查摘要</view>
<scroll-view scroll-y class="summary-body">
<rich-text :nodes="summaryContent"></rich-text>
</scroll-view>
<view class="summary-actions">
<u-button v-if="summaryHtmlUrl" type="primary" size="small" @click="openUrl(summaryHtmlUrl)">查看完整报告</u-button>
<u-button size="small" @click="showSummary = false">关闭</u-button>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import uititle from '@/components/common/title'
import dayjs from 'dayjs'
export default {
components: { uititle },
data() {
return {
reportList: [],
loading: false,
showSummary: false,
summaryContent: '',
summaryHtmlUrl: '',
statusMap: {
uploaded: '待审查',
reviewing: '排队中',
processing: '审查中',
completed: '已完成',
failed: '失败'
}
}
},
onShow() {
this.queryReports()
},
methods: {
async queryReports() {
this.loading = true
try {
const res = await vk.callFunction({
url: 'client/ai/pub/getMyReports',
data: { pageIndex: 1, pageSize: 50 }
})
if (res.code === 0 && res.data && res.data.rows) {
this.reportList = res.data.rows.map(r => ({
fileName: r.file_name,
fileSize: r.file_size,
fileUrl: r.file_url || '',
htmlUrl: r.html_url || '',
time: dayjs(r._add_time && r._add_time['$date'] ? r._add_time['$date'] : r._add_time).format('YYYY-MM-DD HH:mm'),
amount: r.points_used || 0,
result: r.result,
status: r.status,
recordId: r._id
}))
}
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
}
this.loading = false
},
viewSummary(r) {
this.summaryContent = this.formatContent(r.result)
this.summaryHtmlUrl = r.htmlUrl
this.showSummary = true
},
formatContent(text) {
if (!text) return '<p>暂无审查结果</p>'
let html = text
html = html.replace(/^###\s+(.+)$/gm, '<h4 style="font-size:15px;margin:12px 0 6px;">$1</h4>')
html = html.replace(/^##\s+(.+)$/gm, '<h3 style="font-size:16px;margin:16px 0 8px;">$1</h3>')
html = html.replace(/\*\*(.*?)\*\*/g, '<strong style="color:#a92924;">$1</strong>')
html = html.replace(/^[\-\•]\s+(.+)$/gm, '<div style="padding-left:12px;">• $1</div>')
html = html.replace(/^(\d+)\.\s+(.+)$/gm, '<div style="padding-left:12px;">$1. $2</div>')
html = html.replace(/\n/g, '<br>')
return html
},
openUrl(url) {
if (url) {
// #ifdef H5
window.open(url, '_blank')
// #endif
// #ifndef H5
uni.navigateTo({ url: '/pages/ai/webview?url=' + encodeURIComponent(url) })
// #endif
}
}
}
}
</script>
<style lang="scss" scoped>
.page-wrap {
min-height: 100vh;
background: #f5f5f5;
}
.action-bar {
padding: 20rpx 30rpx;
display: flex;
justify-content: flex-end;
}
.empty-box {
text-align: center;
padding: 120rpx 30rpx;
}
.empty-icon {
font-size: 80rpx;
}
.empty-text {
font-size: 30rpx;
font-weight: 600;
margin-top: 16rpx;
}
.empty-hint {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.loading-box {
text-align: center;
padding: 60rpx 0;
}
.loading-text {
display: block;
font-size: 28rpx;
margin-top: 16rpx;
}
.report-item {
background: #fff;
margin: 16rpx 30rpx;
padding: 24rpx;
border-radius: 12rpx;
}
.report-header {
display: flex;
align-items: center;
gap: 16rpx;
}
.report-name {
flex: 1;
font-size: 28rpx;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.status-tag {
font-size: 22rpx;
padding: 4rpx 16rpx;
border-radius: 8rpx;
flex-shrink: 0;
}
.status-uploaded { background: #f0f0f0; color: #999; }
.status-reviewing { background: #fdf6ec; color: #e6a23c; }
.status-processing { background: #fdf6ec; color: #e6a23c; }
.status-completed { background: #f0f9eb; color: #67c23a; }
.status-failed { background: #fef0f0; color: #f56c6c; }
.report-meta {
font-size: 22rpx;
color: #999;
margin-top: 8rpx;
}
.report-actions {
display: flex;
gap: 16rpx;
margin-top: 16rpx;
flex-wrap: wrap;
}
.action-btn {
font-size: 24rpx;
color: #a92924;
padding: 8rpx 20rpx;
border: 1rpx solid #a92924;
border-radius: 8rpx;
}
.action-btn:active {
background: #a92924;
color: #fff;
}
.summary-popup {
padding: 30rpx;
max-height: 70vh;
}
.summary-title {
font-size: 32rpx;
font-weight: 600;
margin-bottom: 20rpx;
}
.summary-body {
max-height: 50vh;
font-size: 26rpx;
line-height: 1.8;
}
.summary-actions {
display: flex;
gap: 16rpx;
margin-top: 24rpx;
justify-content: center;
}
</style>
+359
View File
@@ -0,0 +1,359 @@
<template>
<view class="page-wrap">
<uititle title="AI 合同审查"></uititle>
<!-- 积分提示 -->
<view class="notice-bar">
<text>💎 当前积分:{{ pointsBalance }}|每 100KB 约 200 积分</text>
</view>
<!-- 免责声明 -->
<view class="disclaimer-bar">
<text>⚠️ 请确保合同内容清晰可见,如因不清晰导致分析失败,积分正常消耗。</text>
</view>
<!-- 上传区 -->
<view v-if="!reviewFile" class="upload-area" @click="selectReviewFile">
<view class="upload-icon">📤</view>
<view class="upload-text">上传合同文件</view>
<view class="upload-hint">支持 PDF / Word(.doc .docx),最大 20MB</view>
</view>
<!-- 上传中 -->
<view v-if="reviewUploading" class="loading-box">
<u-loading-icon size="48"></u-loading-icon>
<text class="loading-text">正在上传文件到审查系统...</text>
</view>
<!-- 文件信息 + 操作 -->
<view v-if="reviewFile && !reviewUploading" class="file-section">
<view class="file-card">
<view class="file-name">📄 {{ reviewFile.name }}</view>
<view class="file-size">{{ formatFileSize(reviewFile.size) }}</view>
</view>
<view class="review-mode">
<view class="mode-item selected">
<view class="mode-icon">🔍</view>
<view class="mode-info">
<view class="mode-title">标准审查</view>
<view class="mode-desc">风险条款识别 · 合规性检查</view>
</view>
</view>
</view>
<view class="p-20">
<u-button type="primary" shape="circle" :loading="reviewLoading"
:disabled="pointsBalance < reviewPoints + 200"
@click="startReview">
{{ reviewLoading ? '审查中...' : '开始审查(约 ' + reviewPoints + ' 积分)' }}
</u-button>
<view v-if="pointsBalance < reviewPoints + 200" class="warn-text">
积分不足,当前余额 {{ pointsBalance }},需要 {{ reviewPoints }} 积分且审查后余额需保留至少 200 积分
</view>
</view>
</view>
<!-- 审查中 -->
<view v-if="reviewLoading" class="loading-box">
<u-loading-icon size="48"></u-loading-icon>
<text class="loading-text">🤖 AI 正在分析合同,请稍候...</text>
<text class="loading-hint">预计 3-5 分钟,可前往「我的报告」查看进度</text>
</view>
</view>
</template>
<script>
import uititle from '@/components/common/title'
export default {
components: { uititle },
data() {
return {
pointsBalance: 0,
reviewFile: null,
reviewFileId: null,
reviewRecordId: null,
reviewUploading: false,
reviewLoading: false,
reviewPoints: 200,
reviewProgress: 0
}
},
onShow() {
this.getPointsBalance()
},
methods: {
async getPointsBalance() {
const res = await vk.callFunction({ url: 'client/points/kh/getBalance' })
if (res.code === 0 && res.data) {
this.pointsBalance = res.data.balance || 0
}
},
selectReviewFile() {
uni.chooseFile({
count: 1,
type: 'file',
extension: ['.pdf', '.doc', '.docx'],
success: (res) => {
const filePath = res.tempFilePaths[0]
const fileName = res.tempFiles[0].name || filePath.split('/').pop()
const fileSize = res.tempFiles[0].size
if (fileSize > 20 * 1024 * 1024) {
uni.showToast({ title: '文件大小超过 20MB', icon: 'none' })
return
}
this.reviewFile = { name: fileName, size: fileSize, path: filePath }
this.reviewFileId = null
this.reviewPoints = Math.max(200, Math.ceil(fileSize / (100 * 1024)) * 200)
this.uploadFile(filePath, fileName, fileSize)
}
})
},
async uploadFile(filePath, fileName, fileSize) {
this.reviewUploading = true
try {
const base64 = await this.fileToBase64(filePath)
const res = await vk.callFunction({
url: 'client/ai/pub/review',
data: {
file_base64: base64,
file_name: fileName,
file_size: fileSize,
upload_only: true
}
})
if (res.code === 0 && res.data && res.data.file_id) {
this.reviewFileId = res.data.file_id
this.reviewRecordId = res.data.record_id
uni.showToast({ title: '文件上传成功', icon: 'success' })
} else {
uni.showToast({ title: res.msg || '上传失败', icon: 'none' })
this.reviewFile = null
}
} catch (e) {
uni.showToast({ title: '上传异常', icon: 'none' })
this.reviewFile = null
}
this.reviewUploading = false
},
fileToBase64(filePath) {
return new Promise((resolve, reject) => {
// #ifdef H5
const xhr = new XMLHttpRequest()
xhr.open('GET', filePath, true)
xhr.responseType = 'blob'
xhr.onload = () => {
const reader = new FileReader()
reader.onload = () => resolve(reader.result.split(',')[1])
reader.onerror = reject
reader.readAsDataURL(xhr.response)
}
xhr.onerror = reject
xhr.send()
// #endif
// #ifndef H5
uni.getFileSystemManager().readFile({
filePath,
encoding: 'base64',
success: (res) => resolve(res.data),
fail: reject
})
// #endif
})
},
async startReview() {
if (!this.reviewFileId || !this.reviewRecordId) {
uni.showToast({ title: '请先上传文件', icon: 'none' })
return
}
// 积分余额检查
const balanceRes = await vk.callFunction({ url: 'client/points/kh/getBalance' })
if (balanceRes.code !== 0 || !balanceRes.data || balanceRes.data.balance < 200) {
uni.showToast({ title: '积分不足,请先充值', icon: 'none' })
return
}
this.reviewLoading = true
try {
const res = await vk.callFunction({
url: 'client/ai/pub/review',
data: {
record_id: this.reviewRecordId,
file_id: this.reviewFileId,
file_name: this.reviewFile.name,
file_size: this.reviewFile.size
}
})
if (res.code === 0) {
uni.showModal({
title: '审查已提交',
content: 'AI 正在分析中,预计 3-5 分钟完成。您可以在「我的报告」中查看结果。',
showCancel: false,
confirmText: '知道了',
success: () => {
this.resetReview()
uni.navigateBack()
}
})
} else {
uni.showToast({ title: res.msg || '发起审查失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '请求异常', icon: 'none' })
}
this.reviewLoading = false
},
resetReview() {
this.reviewFile = null
this.reviewFileId = null
this.reviewRecordId = null
this.reviewUploading = false
this.reviewLoading = false
this.reviewProgress = 0
},
formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B'
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
}
}
}
</script>
<style lang="scss" scoped>
.page-wrap {
min-height: 100vh;
background: #f5f5f5;
}
.notice-bar {
background: #fff8e1;
padding: 20rpx 30rpx;
font-size: 24rpx;
color: #b8860b;
}
.disclaimer-bar {
background: #fef0f0;
padding: 20rpx 30rpx;
font-size: 22rpx;
color: #f56c6c;
}
.upload-area {
margin: 30rpx;
padding: 80rpx 30rpx;
border: 4rpx dashed #d0d0d0;
border-radius: 16rpx;
text-align: center;
background: #fff;
}
.upload-area:active {
border-color: #a92924;
background: #fdf0f0;
}
.upload-icon {
font-size: 80rpx;
}
.upload-text {
font-size: 32rpx;
font-weight: 600;
margin-top: 16rpx;
}
.upload-hint {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.loading-box {
text-align: center;
padding: 60rpx 30rpx;
}
.loading-text {
display: block;
font-size: 28rpx;
margin-top: 16rpx;
}
.loading-hint {
display: block;
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.file-section {
margin: 30rpx;
}
.file-card {
background: #f9f9f9;
padding: 24rpx;
border-radius: 12rpx;
display: flex;
align-items: center;
gap: 16rpx;
}
.file-name {
flex: 1;
font-size: 28rpx;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-size {
font-size: 24rpx;
color: #999;
flex-shrink: 0;
}
.review-mode {
margin-top: 24rpx;
}
.mode-item {
display: flex;
align-items: center;
gap: 20rpx;
padding: 24rpx;
border: 2rpx solid #a92924;
border-radius: 12rpx;
background: #fdf0f0;
}
.mode-icon {
font-size: 40rpx;
}
.mode-title {
font-size: 28rpx;
font-weight: 600;
}
.mode-desc {
font-size: 22rpx;
color: #999;
margin-top: 4rpx;
}
.warn-text {
text-align: center;
font-size: 24rpx;
color: #f56c6c;
margin-top: 16rpx;
}
</style>
+56 -2
View File
@@ -15,15 +15,32 @@
<text class="text-main">您剩余金久信签约宝次数: {{ userInfo.qybNum }}次</text> <text class="text-main">您剩余金久信签约宝次数: {{ userInfo.qybNum }}次</text>
<view class="qyb-action-row flex justify-start items-center mt-20"> <view class="qyb-action-row flex justify-start items-center mt-20">
<view class="qyb-buy-action"> <view class="qyb-buy-action">
<u-button size="mini" type="primary" @click.native="dialogVisible = true" <u-button size="max" type="primary" @click.native="dialogVisible = true"
:custom-style="{padding: 0, width: '100%'}">立即购买</u-button> :custom-style="{padding: 0, width: '100%'}">立即购买</u-button>
</view> </view>
<view class="qyb-log-action ml-25"> <view class="qyb-log-action ml-25">
<u-button size="mini" type="success" @click.native="openLog" <u-button size="max" type="success" @click.native="openLog"
:custom-style="{padding: 0, width: '100%'}">明细</u-button> :custom-style="{padding: 0, width: '100%'}">明细</u-button>
</view> </view>
</view> </view>
</view> </view>
<view class="pb-30">
<text class="text-main">您AI积分剩余: {{ pointsBalance }}积分</text>
<view class="qyb-action-row flex justify-start items-center mt-20" style="display: flex;justify-content:space-between;">
<view class="qyb-buy-action">
<u-button size="max" type="warning" @click="vk.navigateTo('/pages/ai/review')"
:custom-style="{padding: 0, width: '100%'}">合同审查</u-button>
</view>
<view class="qyb-buy-action">
<u-button size="max" type="success" @click="vk.navigateTo('/pages/ai/reports')"
:custom-style="{padding: 0, width: '100%'}">我的报告</u-button>
</view>
<view class="qyb-buy-action">
<u-button size="max" type="primary" @click="vk.navigateTo('/pages/ai/points')"
:custom-style="{padding: 0, width: '100%'}">积分充值</u-button>
</view>
</view>
</view>
<view class="text-main mt-10">温馨提示:尊敬的用户如果您的剩余金久信签约宝次数为0次,请先进行购买,再进行签约。</view> <view class="text-main mt-10">温馨提示:尊敬的用户如果您的剩余金久信签约宝次数为0次,请先进行购买,再进行签约。</view>
<view class="card m-20"> <view class="card m-20">
<view class="flex justify-between items-center" @click="showSignIntro = !showSignIntro"> <view class="flex justify-between items-center" @click="showSignIntro = !showSignIntro">
@@ -347,6 +364,10 @@
</view> </view>
</el-dialog> </el-dialog>
<collapse></collapse> <collapse></collapse>
<!-- AI 客服悬浮按钮 -->
<view class="ai-float-btn" @click="openAiChat">
<text class="ai-float-icon">🤖</text>
</view>
</view> </view>
</template> </template>
@@ -381,6 +402,7 @@ export default {
userInfo: { userInfo: {
qybNum: 0 qybNum: 0
}, },
pointsBalance: 0,
pdfUrl: '', pdfUrl: '',
show: false, show: false,
showPdf: false, showPdf: false,
@@ -801,6 +823,18 @@ export default {
urls: [row.payVoucher], urls: [row.payVoucher],
}) })
}, },
openAiChat() {
uni.navigateTo({ url: '/pages/ai/chat' })
},
goTo(url) {
uni.navigateTo({ url })
},
async getPointsBalance() {
const res = await vk.callFunction({ url: 'client/points/kh/getBalance' })
if (res.code === 0 && res.data) {
this.pointsBalance = res.data.balance || 0
}
},
}, },
onShow() { onShow() {
this.getQybPackage() this.getQybPackage()
@@ -808,6 +842,7 @@ export default {
this.getSignFlow() this.getSignFlow()
this.getSignTips() this.getSignTips()
this.getUserInfo() this.getUserInfo()
this.getPointsBalance()
if (uni.getStorageSync('signInfo')) { if (uni.getStorageSync('signInfo')) {
this.formData = JSON.parse(uni.getStorageSync('signInfo')) this.formData = JSON.parse(uni.getStorageSync('signInfo'))
if (this.formData.signEndDate) this.signEndDate = dayjs(this.formData.signEndDate).format('YYYY-MM-DD') if (this.formData.signEndDate) this.signEndDate = dayjs(this.formData.signEndDate).format('YYYY-MM-DD')
@@ -845,4 +880,23 @@ page {
.qyb-log-action { .qyb-log-action {
flex: 1; flex: 1;
} }
.ai-float-btn {
position: fixed;
bottom: 195px;
right: 30rpx;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background: linear-gradient(135deg, #a92924, #d4574e);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 20rpx rgba(169, 41, 36, 0.4);
z-index: 999;
}
.ai-float-icon {
font-size: 48rpx;
}
</style> </style>
+12 -2
View File
@@ -41,6 +41,9 @@ importers:
normalize-wheel: normalize-wheel:
specifier: ^1.0.1 specifier: ^1.0.1
version: 1.0.1 version: 1.0.1
pdfh5:
specifier: ^3.0.0
version: 3.0.0
pdfjs-dist: pdfjs-dist:
specifier: 2.5.207 specifier: 2.5.207
version: 2.5.207 version: 2.5.207
@@ -591,6 +594,7 @@ packages:
crypto-js@4.2.0: crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained.
csstype@3.1.3: csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -869,7 +873,7 @@ packages:
glob@7.2.3: glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
gopd@1.2.0: gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
@@ -1319,6 +1323,7 @@ packages:
path-dirname@1.0.2: path-dirname@1.0.2:
resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
path-exists@3.0.0: path-exists@3.0.0:
resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
@@ -1332,6 +1337,9 @@ packages:
resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==}
engines: {node: '>=0.12'} engines: {node: '>=0.12'}
pdfh5@3.0.0:
resolution: {integrity: sha512-R1cmlbbxJQP0S7CqbLR9+pSQ7nmCTH/VAjvqhXZErxgaJ1h4K2fj5V600sQPF+fMXc636E+GlqJdQPG4ur+vkw==}
pdfjs-dist@2.5.207: pdfjs-dist@2.5.207:
resolution: {integrity: sha512-xGDUhnCYPfHy+unMXCLCJtlpZaaZ17Ew3WIL0tnSgKFUZXHAPD49GO9xScyszSsQMoutNDgRb+rfBXIaX/lJbw==} resolution: {integrity: sha512-xGDUhnCYPfHy+unMXCLCJtlpZaaZ17Ew3WIL0tnSgKFUZXHAPD49GO9xScyszSsQMoutNDgRb+rfBXIaX/lJbw==}
@@ -1786,7 +1794,7 @@ packages:
uuid@3.4.0: uuid@3.4.0:
resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
hasBin: true hasBin: true
verror@1.10.0: verror@1.10.0:
@@ -3371,6 +3379,8 @@ snapshots:
safe-buffer: 5.2.1 safe-buffer: 5.2.1
sha.js: 2.4.11 sha.js: 2.4.11
pdfh5@3.0.0: {}
pdfjs-dist@2.5.207: {} pdfjs-dist@2.5.207: {}
pdfjs-dist@2.6.347: {} pdfjs-dist@2.6.347: {}
+3
View File
@@ -0,0 +1,3 @@
allowBuilds:
core-js: set this to true or false
es5-ext: set this to true or false
@@ -0,0 +1,23 @@
'use strict';
const querystring = require('querystring');
exports.main = async (event, context) => {
//event为客户端上传的参数
console.log('event : ', event)
const {
body
} = event
let obj = querystring.parse(body);
// 验证签名
// Base64(SHA1(app_id +MD5(timestamp)+SHA1(app_secret+authenticationType+certStatus+customerId+serialNo+status+statusDesc)))
let callFunctionRes = await uniCloud.callFunction({
name: "router",
data: {
$url: "client/fadada.pub_contractNotify",
data: obj
}
});
return callFunctionRes
};
@@ -0,0 +1,7 @@
{
"name": "fadada_contract_notify",
"dependencies": {},
"extensions": {
"uni-cloud-jql": {}
}
}
@@ -0,0 +1,24 @@
'use strict';
const querystring = require('querystring');
exports.main = async (event, context) => {
//event为客户端上传的参数
console.log('event : ', event)
const {
body
} = event
let obj = querystring.parse(body);
console.log('fadada origin obj : ', obj)
// 验证签名
// Base64(SHA1(app_id +MD5(timestamp)+SHA1(app_secret+authenticationType+certStatus+customerId+serialNo+status+statusDesc)))
let callFunctionRes = await uniCloud.callFunction({
name: "router",
data: {
$url: "client/fadada.pub_verifyNotify",
data: obj
}
});
return callFunctionRes
};
@@ -0,0 +1,7 @@
{
"name": "fadada_verify_notify",
"dependencies": {},
"extensions": {
"uni-cloud-jql": {}
}
}
@@ -0,0 +1,12 @@
{
"triggers": [
{
"name": "http",
"type": "http",
"config": {
"path": "/review-stream",
"method": ["POST"]
}
}
]
}
@@ -0,0 +1,106 @@
'use strict';
exports.main = async (event, context) => {
// uniCloud HTTP 触发器:event 本身就是请求信息
// event.httpMethod = 'GET'/'POST'/'OPTIONS'
// event.body = 请求体
// event.headers = 请求头
// context.callbackWaitsForEmptyEventLoop = true 保持连接
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400'
};
// 处理 CORS 预检
if (event.httpMethod === 'OPTIONS') {
return {
statusCode: 204,
headers: corsHeaders,
body: ''
};
}
// 设置等待空事件循环(保持 SSE 连接)
context.callbackWaitsForEmptyEventLoop = false;
// 解析请求体
let body = {};
try {
const raw = event.body || '';
if (event.isBase64Encoded) {
body = JSON.parse(Buffer.from(raw, 'base64').toString());
} else {
try { body = JSON.parse(raw); } catch (e) {
const params = new URLSearchParams(raw);
for (const [k, v] of params) body[k] = v;
}
}
} catch (e) {}
const { file_id, user_id, file_name, file_size, record_id } = body;
if (!file_id) {
return {
statusCode: 400,
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
body: JSON.stringify({ error: '缺少 file_id' })
};
}
const COZE_TOKEN = 'sat_OiXlI4Da5Q99fxmul6pNfExmA6hR898UbxBDwrvjZ638APxRSlFnXbz6zyFedKNG';
const BOT_ID = '7689821072762011698';
const objectString = JSON.stringify([
{ type: 'file', file_id: file_id },
{ type: 'text', text: '请审查这份合同' }
]);
// 调用扣子(流式)
try {
const chatRes = await uniCloud.httpclient.request('https://api.coze.cn/v3/chat', {
method: 'POST',
dataType: 'text',
contentType: 'json',
timeout: 300000,
headers: { 'Authorization': 'Bearer ' + COZE_TOKEN },
data: {
bot_id: BOT_ID,
user_id: user_id || 'anonymous',
stream: true,
auto_save_history: true,
additional_messages: [{
role: 'user',
content: objectString,
content_type: 'object_string'
}]
}
});
// 返回 SSE 格式
const text = chatRes.data || '';
const sseBody = text.split('\n').map(line => {
if (line.startsWith('data:')) return line + '\n\n';
return '';
}).join('') + 'data: [DONE]\n\n';
return {
statusCode: 200,
headers: {
...corsHeaders,
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
},
body: sseBody
};
} catch (e) {
return {
statusCode: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
body: JSON.stringify({ error: e.message })
};
}
};
@@ -0,0 +1,6 @@
{
"name": "jjxReviewStream",
"version": "1.0.0",
"description": "合同审查流式输出云函数",
"main": "index.js"
}
@@ -0,0 +1,239 @@
'use strict';
// 定时任务:每分钟检查 reviewing 状态的记录,触发审查
const db = uniCloud.database();
const _ = db.command;
// 导入审查执行函数(从 router 的 service 目录)
// 注意:定时任务是独立云函数,不能直接 require router 的 service
// 所以把审查逻辑直接写在这里
const COZE_TOKEN = 'sat_OiXlI4Da5Q99fxmul6pNfExmA6hR898UbxBDwrvjZ638APxRSlFnXbz6zyFedKNG';
const BOT_ID = '7689821072762011698';
async function doReview(record) {
const { _id: record_id, file_id, user_id, file_name, file_size } = record;
const objectString = JSON.stringify([
{ type: 'file', file_id: file_id },
{ type: 'text', text: '请审查这份合同' }
]);
try {
// 1. 非流式发起对话(立即返回 chat_id)
const chatRes = await uniCloud.httpclient.request('https://api.coze.cn/v3/chat', {
method: 'POST',
dataType: 'json',
contentType: 'json',
timeout: 30000,
headers: { 'Authorization': 'Bearer ' + COZE_TOKEN },
data: {
bot_id: BOT_ID,
user_id: user_id || 'anonymous',
stream: false,
auto_save_history: true,
additional_messages: [{
role: 'user',
content: objectString,
content_type: 'object_string'
}]
}
});
const chatData = chatRes.data && chatRes.data.data;
const chatId = chatData && chatData.id;
const conversationId = chatData && chatData.conversation_id;
console.log('[审查] chat_id:', chatId, 'conversation_id:', conversationId);
if (!chatId) {
throw new Error('未获取到 chat_id: ' + JSON.stringify(chatRes.data));
}
// 保存 chat_id 和 conversation_id 到数据库
await db.collection('jjx-review-records').doc(record_id).update({
chat_id: chatId,
conversation_id: conversationId || '',
update_time: new Date()
});
console.log('[审查] 已保存 chat_id:', chatId);
// 2. 轮询对话状态(每5秒查一次,最多5分钟)
let answer = '';
let tokenCount = 0;
for (let i = 0; i < 60; i++) {
await new Promise(r => setTimeout(r, 5000));
const statusRes = await uniCloud.httpclient.request(
'https://api.coze.cn/v3/chat/retrieve?chat_id=' + chatId + '&conversation_id=' + conversationId,
{ method: 'GET', dataType: 'json', headers: { 'Authorization': 'Bearer ' + COZE_TOKEN }, timeout: 15000 }
);
const status = statusRes.data && statusRes.data.data && statusRes.data.data.status;
console.log('[审查] 第', i + 1, '次轮询, 状态:', status);
if (status === 'completed') {
// 保存 token 消耗信息
const usage = statusRes.data && statusRes.data.data && statusRes.data.data.usage;
tokenCount = (usage && usage.token_count) || 0;
console.log('[审查] Token 消耗:', tokenCount);
// 3. 获取消息列表
const msgRes = await uniCloud.httpclient.request(
'https://api.coze.cn/v3/chat/message/list?chat_id=' + chatId + '&conversation_id=' + conversationId,
{ method: 'GET', dataType: 'json', headers: { 'Authorization': 'Bearer ' + COZE_TOKEN }, timeout: 15000 }
);
const messages = msgRes.data && msgRes.data.data;
if (Array.isArray(messages)) {
for (const msg of messages) {
if (msg.type === 'answer' && msg.role === 'assistant' && msg.content) {
answer = msg.content; // answer 类型的完整内容
}
if (msg.type === 'tool_response' && msg.content) {
try {
const toolData = JSON.parse(msg.content);
if (toolData.url) answer += '\n\n📎 报告下载:' + toolData.url;
} catch (e) {}
}
}
}
break;
}
if (status === 'failed') {
throw new Error('对话失败');
}
}
if (!answer) answer = '审查未能获取结果,请稍后重试';
console.log('[审查] 结果长度:', answer.length);
// 计算消耗积分
// 积分 = token消耗 / 100(最低1积分)
const pointsUsed = Math.max(1, Math.round(tokenCount / 100));
console.log('[积分] token_count:', tokenCount, '→ 扣除积分:', pointsUsed);
// 扣积分
const userPoints = await db.collection('jjx-user-points').doc(user_id).get();
if (userPoints.data.length && userPoints.data[0].balance >= pointsUsed) {
await db.collection('jjx-user-points').doc(user_id).update({
balance: _.inc(-pointsUsed),
total_spent: _.inc(pointsUsed),
update_time: new Date()
});
const updatedPoints = await db.collection('jjx-user-points').doc(user_id).get();
await db.collection('jjx-points-log').add({
user_id: user_id,
type: 'spend',
amount: -pointsUsed,
balance_after: updatedPoints.data[0] ? updatedPoints.data[0].balance : 0,
reason: '合同审查 — ' + (file_name || '') + '(' + tokenCount + ' token)',
biz_type: 'contract_review',
biz_id: record_id,
_add_time: new Date()
});
}
// 保存 HTML 报告到云存储
let htmlUrl = '';
try {
let htmlContent = answer;
const htmlMatch = answer.match(/```html\s*([\s\S]*?)```/);
if (htmlMatch && htmlMatch[1]) htmlContent = htmlMatch[1].trim();
if (htmlContent.includes('<!DOCTYPE') || htmlContent.includes('<html')) {
const cloudPath = 'review-reports/' + Date.now() + '_' + (file_name || 'report').replace(/\.[^.]+$/, '') + '.html';
const uploadRes = await uniCloud.uploadFile({
cloudPath: cloudPath,
fileContent: Buffer.from(htmlContent, 'utf-8')
});
if (uploadRes.fileID) {
const urlRes = await uniCloud.getTempFileURL({ fileList: [uploadRes.fileID] });
if (urlRes.fileList && urlRes.fileList[0]) htmlUrl = urlRes.fileList[0].tempFileURL;
}
}
} catch (e) {
console.log('HTML报告上传失败:', e.message);
}
// 更新记录为完成
await db.collection('jjx-review-records').doc(record_id).update({
status: 'completed',
result: answer,
html_url: htmlUrl,
token_count: tokenCount,
points_used: pointsUsed,
conversation_id: conversationId || '',
update_time: new Date()
});
console.log('审查完成:', record_id, file_name);
return { code: 0, msg: '审查完成' };
} catch (e) {
await db.collection('jjx-review-records').doc(record_id).update({
status: 'failed',
result: '审查失败: ' + e.message,
error: e.message,
update_time: new Date()
});
console.error('审查失败:', record_id, e.message);
return { code: -1, msg: '审查失败: ' + e.message };
}
}
exports.main = async (event, context) => {
// 先把卡在 processing 超过10分钟的记录重置为 reviewing(超时保护)
const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000);
const stuckRecords = await db.collection('jjx-review-records')
.where({ status: 'processing', update_time: _.lt(tenMinutesAgo) })
.get();
for (const stuck of stuckRecords.data) {
await db.collection('jjx-review-records').doc(stuck._id).update({
status: 'reviewing',
update_time: new Date()
});
}
// 查询所有 reviewing 状态的记录(超过1分钟的,避免重复触发)
const oneMinuteAgo = new Date(Date.now() - 60 * 1000);
const pendingRecords = await db.collection('jjx-review-records')
.where({
status: 'reviewing',
review_started_at: _.lt(oneMinuteAgo)
})
.limit(5) // 每次最多处理5条
.get();
if (!pendingRecords.data.length) {
return { code: 0, msg: '无待处理记录' };
}
console.log('发现待处理审查记录:', pendingRecords.data.length, '条');
// 逐条处理(串行,避免并发问题)
const results = [];
for (const record of pendingRecords.data) {
// 先标记为 processing,避免重复触发
await db.collection('jjx-review-records').doc(record._id).update({
status: 'processing',
update_time: new Date()
});
try {
const result = await doReview(record);
results.push({ record_id: record._id, ...result });
} catch (e) {
// 审查失败,重置为 reviewing 以便下次重试
await db.collection('jjx-review-records').doc(record._id).update({
status: 'reviewing',
update_time: new Date()
});
console.error('审查异常,已重置状态:', record._id, e.message);
results.push({ record_id: record._id, code: -1, msg: e.message });
}
}
return { code: 0, msg: '处理完成', data: results };
};
@@ -0,0 +1,4 @@
// 本文件中的json内容将在云函数【运行】时作为参数传给云函数。
// 配置教程参考:https://uniapp.dcloud.net.cn/uniCloud/rundebug.html#runparam
{
}
@@ -0,0 +1,19 @@
{
"name": "jjxReviewTimer",
"version": "1.0.0",
"description": "合同审查定时任务",
"main": "index.js",
"cloudfunction-config": {
"memorySize": 256,
"timeout": 600,
"triggers": [
{
"name": "myTrigger",
"type": "timer",
"config": "0 */1 * * * * *"
}
],
"path": "",
"runtime": "Nodejs16"
}
}
@@ -0,0 +1,25 @@
'use strict';
const querystring = require('querystring');
exports.main = async (event, context) => {
//event为客户端上传的参数
console.log('event : ', event)
const {
body
} = event
const obj = querystring.parse(body);
// // 验证签名
// // Base64(SHA1(app_id +MD5(timestamp)+SHA1(app_secret+authenticationType+certStatus+customerId+serialNo+status+statusDesc)))
//
await uniCloud.callFunction({
name: "router",
data: {
$url: "client/payment.pub_payNotify",
data: obj
}
});
//
// return callFunctionRes
// console.log(obj)
return 'SUCCESS'
};
@@ -0,0 +1,7 @@
{
"name": "pay_notify",
"dependencies": {},
"extensions": {
"uni-cloud-jql": {}
}
}
@@ -0,0 +1,17 @@
'use strict';
// 涉及的表名
const dbName = {
spotCategory: "jjx-spot-category", //商品-分类表
spotGoods: "jjx-spot-goods", //商品-现货表
contract: "jjx-contract", // 合同
userContract: "jjx-user-contract", // 用户合同
enquirySheet: "jjx-enquiry-sheet", // 询价单
enquiryQuote: "jjx-enquiry-quotre", // 报价单
enquiryTemplate: "jjx-enquiry-template", // 询价模板
enquiryAttributes: "jjx-enquiry-attributes", // 询价模板属性
user: "uni-id-users", //用户
seal: "jjx-seal", //印章
processSheet: "jjx-process-sheet", //找加工
processQuote: "jjx-process-quote", //找加工报价单
};
module.exports = dbName;
@@ -0,0 +1,463 @@
/**
*
*/
// 涉及的表名
const dbName = {
contractDao: "jjx-contract", // 请在此处填写表中文含义
};
var dao = {};
var util = {};
// 初始化
dao.init = function(obj) {
util = obj;
}
/**
* 查 - 根据id获取单条记录
* @param {String} _id
* @param {Object} fieldJson 字段显示规则
* 调用示例
* let contractDaoInfo = await vk.daoCenter.contractDaoDao.findById(_id);
* 或
let contractDaoInfo = await vk.daoCenter.contractDaoDao.findById({
db: transaction,
id: _id
});
*/
dao.findById = async (_id, fieldJson) => {
let { vk, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
if (typeof _id === "object") {
// 支持事务
res = await vk.baseDao.findById({
..._id,
dbName: dbName.contractDao,
});
} else {
// 不支持事务
res = await vk.baseDao.findById({
dbName: dbName.contractDao,
id: _id,
fieldJson
});
}
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 根据whereJson获取单条记录
* @param {Object} whereJson 条件
* @param {Object} fieldJson 字段显示规则
* 调用示例
let contractDaoInfo = await vk.daoCenter.contractDaoDao.findByWhereJson({
});
*/
dao.findByWhereJson = async (whereJson, fieldJson) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.findByWhereJson({
dbName: dbName.contractDao,
whereJson,
fieldJson
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 增 - 添加一条记录
* @param {Object} dataJson 添加的数据
* 调用示例
await vk.daoCenter.contractDaoDao.add({
});
或
* 调用示例
await vk.daoCenter.contractDaoDao.add({
db: transaction,
dataJson: {
}
});
*/
dao.add = async (obj) => {
let { vk, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
if (obj.db && obj.dataJson) {
// 支持事务
res = await vk.baseDao.add({
...obj,
dbName: dbName.contractDao,
});
} else {
// 不支持事务
res = await vk.baseDao.add({
dbName: dbName.contractDao,
dataJson: obj
});
}
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 增 - 添加多条记录
* @param {Object} dataJson 添加的数据
* 调用示例
await vk.daoCenter.contractDaoDao.adds(dataArr);
*/
dao.adds = async (dataArr) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.adds({
dbName: dbName.contractDao,
dataJson: dataArr
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 删 - 删除多条记录
* @param {Object} whereJson 条件
* 调用示例
await vk.daoCenter.contractDaoDao.del({
});
*/
dao.del = async (whereJson) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.del({
dbName: dbName.contractDao,
whereJson
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 删 - 据ID删除单条数据
* @param {String} _id
* 调用示例
await vk.daoCenter.contractDaoDao.deleteById(_id);
或
await vk.daoCenter.contractDaoDao.deleteById(_id, transaction);
*/
dao.deleteById = async (_id, db) => {
let { vk, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.deleteById({
db,
dbName: dbName.contractDao,
id: _id
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 改 - 批量修改
* @param {Object} whereJson 条件
* @param {Object} dataJson 修改的数据
* 调用示例
await vk.daoCenter.contractDaoDao.update({
whereJson:{
},
dataJson:{
}
});
*/
dao.update = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.update({
...obj,
dbName: dbName.contractDao,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 改 - 根据ID修改数据
* @param {String} _id
* @param {Object} dataJson 修改的数据
* 调用示例
await vk.daoCenter.contractDaoDao.updateById({
id: _id,
dataJson: {
}
});
*/
dao.updateById = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.updateById({
...obj,
dbName: dbName.contractDao
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 改 - 更新并返回更新后的数据(无论条件匹配到多少条记录,只会修改第一条记录,同时返回修改后的数据)
* @param {Object} whereJson 条件
* @param {Object} dataJson 修改的数据
* 调用示例
await vk.daoCenter.contractDaoDao.updateAndReturn({
whereJson:{
},
dataJson:{
}
});
*/
dao.updateAndReturn = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.updateAndReturn({
...obj,
dbName: dbName.contractDao
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 根据ID判断存在则修改,不存在则添加
* @param {String} id 如果传了id参数,则会与dataJson中的_id判断是否一致,不一致会报错
* @param {Object} dataJson 修改的数据
* 调用示例
await vk.daoCenter.contractDaoDao.setById({
dataJson: {
}
});
*/
dao.setById = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.setById({
...obj,
dbName: dbName.contractDao
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 获取记录总条数
* @param {Object} whereJson 条件
* 调用示例
await vk.daoCenter.contractDaoDao.count(whereJson);
*/
dao.count = async (whereJson) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.count({
dbName: dbName.contractDao,
whereJson
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 求和
* @param {String} fieldName 需要求和的字段名
* @param {Object} whereJson 筛选条件
* 调用示例
let contractDaoSum = await vk.daoCenter.contractDaoDao.sum({
fieldName: "",
whereJson: {
}
});
*/
dao.sum = async (obj) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.sum({
...obj,
dbName: dbName.contractDao,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 求最大值
* @param {String} fieldName 需要求最大值的字段名
* @param {Object} whereJson 筛选条件
* 调用示例
let contractDaoMax = await vk.daoCenter.contractDaoDao.max({
fieldName: "",
whereJson: {
}
});
*/
dao.max = async (obj) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.max({
...obj,
dbName: dbName.contractDao,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 求最小值
* @param {String} fieldName 需要求最小值的字段名
* @param {Object} whereJson 筛选条件
* 调用示例
let contractDaoMin = await vk.daoCenter.contractDaoDao.min({
fieldName: "",
whereJson: {
}
});
*/
dao.min = async (obj) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.min({
...obj,
dbName: dbName.contractDao,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 求最平均值
* @param {String} fieldName 需要求最平均值的字段名
* @param {Object} whereJson 筛选条件
* 调用示例
let contractDaoAvg = await vk.daoCenter.contractDaoDao.avg({
fieldName: "",
whereJson: {
}
});
*/
dao.avg = async (obj) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.avg({
...obj,
dbName: dbName.contractDao,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 获取数据列表
* 调用示例
let contractDaoList = await vk.daoCenter.contractDaoDao.select({
pageIndex:1,
pageSize:20,
getMain:false,
whereJson:{
},
fieldJson:{},
sortArr: [{"name": "_add_time", "type":"desc" }],
});
*/
dao.select = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.select({
...obj,
dbName: dbName.contractDao
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 获取数据列表
* 调用示例
let contractDaoList = await vk.daoCenter.contractDaoDao.selects({
pageIndex:1,
pageSize:20,
getMain:false,
whereJson:{
},
fieldJson:{},
sortArr: [{"name": "_add_time", "type":"desc" }],
// 副表列表
foreignDB:[
{
dbName:"副表表名",
localKey:"主表外键名",
foreignKey:"副表外键名",
as:"副表as字段",
limit:1
}
]
});
*/
dao.selects = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.selects({
...obj,
dbName: dbName.contractDao
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 获取数据列表
* 调用示例
res = await vk.daoCenter.contractDaoDao.getTableData({
data
});
*/
dao.getTableData = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.getTableData({
...obj,
dbName: dbName.contractDao
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
module.exports = dao;
@@ -0,0 +1,461 @@
/**
*
*/
// 涉及的表名
const dbName = {
userContract: "jjx-user-contract", // 用户合同关联表
};
var dao = {};
var util = {};
// 初始化
dao.init = function(obj) {
util = obj;
}
/**
* 查 - 根据id获取单条记录
* @param {String} _id
* @param {Object} fieldJson 字段显示规则
* 调用示例
* let userContractInfo = await vk.daoCenter.userContractDao.findById(_id);
* 或
let userContractInfo = await vk.daoCenter.userContractDao.findById({
db: transaction,
id: _id
});
*/
dao.findById = async (_id, fieldJson) => {
let { vk, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
if (typeof _id === "object") {
// 支持事务
res = await vk.baseDao.findById({
..._id,
dbName: dbName.userContract,
});
} else {
// 不支持事务
res = await vk.baseDao.findById({
dbName: dbName.userContract,
id: _id,
fieldJson
});
}
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 根据whereJson获取单条记录
* @param {Object} whereJson 条件
* @param {Object} fieldJson 字段显示规则
* 调用示例
let userContractInfo = await vk.daoCenter.userContractDao.findByWhereJson({
});
*/
dao.findByWhereJson = async (whereJson, fieldJson) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.findByWhereJson({
dbName: dbName.userContract,
whereJson,
fieldJson
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 增 - 添加一条记录
* @param {Object} dataJson 添加的数据
* 调用示例
await vk.daoCenter.userContractDao.add({
});
或
* 调用示例
await vk.daoCenter.userContractDao.add({
db: transaction,
dataJson: {
}
});
*/
dao.add = async (obj) => {
let { vk, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
if (obj.db && obj.dataJson) {
// 支持事务
res = await vk.baseDao.add({
...obj,
dbName: dbName.userContract,
});
} else {
// 不支持事务
res = await vk.baseDao.add({
dbName: dbName.userContract,
dataJson: obj
});
}
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 增 - 添加多条记录
* @param {Object} dataJson 添加的数据
* 调用示例
await vk.daoCenter.userContractDao.adds(dataArr);
*/
dao.adds = async (dataArr) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.adds({
dbName: dbName.userContract,
dataJson: dataArr
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 删 - 删除多条记录
* @param {Object} whereJson 条件
* 调用示例
await vk.daoCenter.userContractDao.del({
});
*/
dao.del = async (whereJson) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.del({
dbName: dbName.userContract,
whereJson
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 删 - 据ID删除单条数据
* @param {String} _id
* 调用示例
await vk.daoCenter.userContractDao.deleteById(_id);
或
await vk.daoCenter.userContractDao.deleteById(_id, transaction);
*/
dao.deleteById = async (_id, db) => {
let { vk, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.deleteById({
db,
dbName: dbName.userContract,
id: _id
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 改 - 批量修改
* @param {Object} whereJson 条件
* @param {Object} dataJson 修改的数据
* 调用示例
await vk.daoCenter.userContractDao.update({
whereJson:{
},
dataJson:{
}
});
*/
dao.update = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.update({
...obj,
dbName: dbName.userContract,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 改 - 根据ID修改数据
* @param {String} _id
* @param {Object} dataJson 修改的数据
* 调用示例
await vk.daoCenter.userContractDao.updateById({
id: _id,
dataJson: {
}
});
*/
dao.updateById = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.updateById({
...obj,
dbName: dbName.userContract
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 改 - 更新并返回更新后的数据(无论条件匹配到多少条记录,只会修改第一条记录,同时返回修改后的数据)
* @param {Object} whereJson 条件
* @param {Object} dataJson 修改的数据
* 调用示例
await vk.daoCenter.userContractDao.updateAndReturn({
whereJson:{
},
dataJson:{
}
});
*/
dao.updateAndReturn = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.updateAndReturn({
...obj,
dbName: dbName.userContract
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 根据ID判断存在则修改,不存在则添加
* @param {String} id 如果传了id参数,则会与dataJson中的_id判断是否一致,不一致会报错
* @param {Object} dataJson 修改的数据
* 调用示例
await vk.daoCenter.userContractDao.setById({
dataJson: {
}
});
*/
dao.setById = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.setById({
...obj,
dbName: dbName.userContract
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 获取记录总条数
* @param {Object} whereJson 条件
* 调用示例
await vk.daoCenter.userContractDao.count(whereJson);
*/
dao.count = async (whereJson) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.count({
dbName: dbName.userContract,
whereJson
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 求和
* @param {String} fieldName 需要求和的字段名
* @param {Object} whereJson 筛选条件
* 调用示例
let userContractSum = await vk.daoCenter.userContractDao.sum({
fieldName: "",
whereJson: {
}
});
*/
dao.sum = async (obj) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.sum({
...obj,
dbName: dbName.userContract,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 求最大值
* @param {String} fieldName 需要求最大值的字段名
* @param {Object} whereJson 筛选条件
* 调用示例
let userContractMax = await vk.daoCenter.userContractDao.max({
fieldName: "",
whereJson: {
}
});
*/
dao.max = async (obj) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.max({
...obj,
dbName: dbName.userContract,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 求最小值
* @param {String} fieldName 需要求最小值的字段名
* @param {Object} whereJson 筛选条件
* 调用示例
let userContractMin = await vk.daoCenter.userContractDao.min({
fieldName: "",
whereJson: {
}
});
*/
dao.min = async (obj) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.min({
...obj,
dbName: dbName.userContract,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 求最平均值
* @param {String} fieldName 需要求最平均值的字段名
* @param {Object} whereJson 筛选条件
* 调用示例
let userContractAvg = await vk.daoCenter.userContractDao.avg({
fieldName: "",
whereJson: {
}
});
*/
dao.avg = async (obj) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.avg({
...obj,
dbName: dbName.userContract,
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 获取数据列表
* 调用示例
let userContractList = await vk.daoCenter.userContractDao.select({
pageIndex:1,
pageSize:20,
getMain:false,
whereJson:{
},
fieldJson:{},
sortArr: [{"name": "_add_time", "type":"desc" }],
});
*/
dao.select = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.select({
...obj,
dbName: dbName.userContract
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 获取数据列表
* 调用示例
let userContractList = await vk.daoCenter.userContractDao.selects({
pageIndex:1,
pageSize:20,
getMain:false,
whereJson:{
},
fieldJson:{},
sortArr: [{"name": "_add_time", "type":"desc" }],
// 副表列表
foreignDB:[
{
dbName:"副表表名",
localKey:"主表外键名",
foreignKey:"副表外键名",
as:"副表as字段",
limit:1
}
]
});
*/
dao.selects = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.selects({
...obj,
dbName: dbName.userContract
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
/**
* 查 - 获取数据列表
* 调用示例
res = await vk.daoCenter.userContractDao.getTableData({
data
});
*/
dao.getTableData = async (obj = {}) => {
let { vk, db, _ } = util;
let res = {};
// 数据库操作开始-----------------------------------------------------------
res = await vk.baseDao.getTableData({
...obj,
dbName: dbName.userContract
});
// 数据库操作结束-----------------------------------------------------------
return res;
};
module.exports = dao;
@@ -377,7 +377,7 @@ let userList = await vk.daoCenter.userDao.select({
}, },
fieldJson:{}, fieldJson:{},
sortArr:[{ "name":"_id", "type":"desc" }], sortArr: [{"name": "_add_time", "type":"desc" }],
}); });
*/ */
dao.select = async (obj = {}) => { dao.select = async (obj = {}) => {
@@ -403,7 +403,7 @@ let userList = await vk.daoCenter.userDao.selects({
}, },
fieldJson:{}, fieldJson:{},
sortArr:[{ "name":"_id", "type":"desc" }], sortArr: [{"name": "_add_time", "type":"desc" }],
// 副表列表 // 副表列表
foreignDB:[ foreignDB:[
{ {
@@ -6,6 +6,7 @@
module.exports = [{ module.exports = [{
id: "returnUserInfo", id: "returnUserInfo",
// 符合下方正则条件的云函数才会进入该中间件
regExp: [ regExp: [
"^user/pub/login(.*)", "^user/pub/login(.*)",
"^user/pub/register(.*)", "^user/pub/register(.*)",
+111
View File
@@ -0,0 +1,111 @@
{
"name": "router",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "router",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
"md5": "^2.3.0",
"pdf-parse": "^1.1.1",
"uni-config-center": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center",
"uni-id": "file:../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id",
"vk-unicloud": "file:../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud"
}
},
"../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center": {
"version": "0.0.3",
"license": "Apache-2.0"
},
"../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id": {
"version": "3.3.28",
"license": "Apache-2.0",
"dependencies": {
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
}
},
"../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud": {
"version": "2.15.3",
"license": "Apache-2.0"
},
"node_modules/charenc": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
"engines": {
"node": "*"
}
},
"node_modules/crypt": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
"engines": {
"node": "*"
}
},
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"deprecated": "Active development of CryptoJS has been discontinued. This library is no longer maintained."
},
"node_modules/dayjs": {
"version": "1.11.23",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz",
"integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ=="
},
"node_modules/is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"node_modules/md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
"dependencies": {
"charenc": "0.0.2",
"crypt": "0.0.2",
"is-buffer": "~1.1.6"
}
},
"node_modules/node-ensure": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz",
"integrity": "sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw=="
},
"node_modules/pdf-parse": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-1.1.4.tgz",
"integrity": "sha512-XRIRcLgk6ZnUbsHsYXExMw+krrPE81hJ6FQPLdBNhhBefqIQKXu/WeTgNBGSwPrfU0v+UCEwn7AoAUOsVKHFvQ==",
"dependencies": {
"node-ensure": "^0.0.0"
},
"engines": {
"node": ">=6.8.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/mehmet-kozan"
}
},
"node_modules/uni-config-center": {
"resolved": "../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center",
"link": true
},
"node_modules/uni-id": {
"resolved": "../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id",
"link": true
},
"node_modules/vk-unicloud": {
"resolved": "../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud",
"link": true
}
}
}
@@ -1,7 +1,7 @@
{ {
"name": "router", "name": "router",
"version": "1.0.0", "version": "1.0.0",
"description": "在router目录下执行 npm i", "description": "【开箱即用】vk-uniCloud-router - 云函数路由模式 - uniCloud开发框架 - 已集成uni-id",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
@@ -10,6 +10,10 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
"md5": "^2.3.0",
"pdf-parse": "^1.1.1",
"uni-config-center": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", "uni-config-center": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center",
"uni-id": "file:../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id", "uni-id": "file:../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id",
"vk-unicloud": "file:../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud" "vk-unicloud": "file:../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud"
@@ -18,11 +22,12 @@
"cloudfunction-config": { "cloudfunction-config": {
"concurrency": 1, "concurrency": 1,
"memorySize": 512, "memorySize": 512,
"path": "", "path": "/http/router",
"timeout": 60, "timeout": 600,
"triggers": [], "triggers": [],
"runtime": "Nodejs12",
"keepRunningAfterReturn": false "keepRunningAfterReturn": false
}, },
"extensions": {} "extensions": {
} "uni-cloud-sms": {}
}
}
@@ -6,8 +6,9 @@
{ {
"uni_id_token":"", "uni_id_token":"",
"$url":"template/openapi/weixin/pub/getTemplateList", "$url":"template/db_api/pub/tree",
"data":{ "data":{
"username":"admin",
"password":"123456"
} }
} }
@@ -0,0 +1,43 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const adKey = parseInt(data.adKey)
const categoryFilterAdKeys = [9, 10, 11, 12, 13, 14, 112, 122]
if ([36, 37, 38].includes(adKey) && !data.spotGoodsId) {
return {code: -1, msg: '请选择现货'}
}
if (categoryFilterAdKeys.includes(adKey) && data.filterMode === 'category' && !(Array.isArray(data.categoryIds) ? data.categoryIds.length : (data.categoryId || data.categoryName))) {
return {code: -1, msg: '请选择分类'}
}
if (categoryFilterAdKeys.includes(adKey) && data.filterMode === 'category' && !(data.region && data.region.province && data.region.province.code)) {
return {code: -1, msg: '请选择区域'}
}
if (![36, 37, 38].includes(adKey) && data.filterMode !== 'category' && data.type === 'company' && !data.companyId) {
return {code: -1, msg: '请选择指定公司'}
}
if (![36, 37, 38].includes(adKey) && data.filterMode !== 'category' && data.type === 'goods' && !data.goodsId) {
return {code: -1, msg: '请选择指定商品'}
}
await vk.baseDao.add({
dbName: 'jjx-ad',
dataJson: data
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/delete 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { uid } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.deleteById({
dbName: 'jjx-ad',
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,60 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/list 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid, pageIndex, pageSize, sortRule} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const whereJson = {}
if (!vk.pubfn.isNull(data.formData) && !vk.pubfn.isNull(data.formData.adKey))
whereJson.adKey = data.formData.adKey
res = await vk.baseDao.selects({
dbName: 'jjx-ad',
pageIndex,
pageSize,
whereJson,
getCount: true,
sortArr: sortRule && sortRule.length ? sortRule : [
{name: "_add_time", type: "desc"},
],
});
for (let i = 0; i < res.rows.length; i++) {
if (res.rows[i].companyId) {
res.rows[i].company = await vk.baseDao.findByWhereJson({
dbName: 'uni-id-users',
whereJson: {
_id: res.rows[i].companyId
},
});
}
if (res.rows[i].goodsId) {
res.rows[i].goods = await vk.baseDao.findByWhereJson({
dbName: 'jjx-goods',
whereJson: {
_id: res.rows[i].goodsId
},
});
}
if (res.rows[i].spotGoodsId) {
res.rows[i].spotGoods = await vk.baseDao.findByWhereJson({
dbName: 'jjx-spot-goods',
whereJson: {
_id: res.rows[i].spotGoodsId
},
});
}
}
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,44 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/update 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const adKey = parseInt(data.adKey)
const categoryFilterAdKeys = [9, 10, 11, 12, 13, 14, 112, 122]
if ([36, 37, 38].includes(adKey) && !data.spotGoodsId) {
return {code: -1, msg: '请选择现货'}
}
if (categoryFilterAdKeys.includes(adKey) && data.filterMode === 'category' && !(Array.isArray(data.categoryIds) ? data.categoryIds.length : (data.categoryId || data.categoryName))) {
return {code: -1, msg: '请选择分类'}
}
if (categoryFilterAdKeys.includes(adKey) && data.filterMode === 'category' && !(data.region && data.region.province && data.region.province.code)) {
return {code: -1, msg: '请选择区域'}
}
if (![36, 37, 38].includes(adKey) && data.filterMode !== 'category' && data.type === 'company' && !data.companyId) {
return {code: -1, msg: '请选择指定公司'}
}
if (![36, 37, 38].includes(adKey) && data.filterMode !== 'category' && data.type === 'goods' && !data.goodsId) {
return {code: -1, msg: '请选择指定商品'}
}
await vk.baseDao.updateById({
dbName: 'jjx-ad',
dataJson: data,
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.add({
dbName: 'jjx-album',
dataJson: data
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/delete 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { uid } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.deleteById({
dbName: 'jjx-album',
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,42 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/list 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid, pageIndex, pageSize, sortRule} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
res = await vk.baseDao.selects({
dbName: 'jjx-album',
pageIndex,
pageSize,
getCount: true,
sortArr: sortRule && sortRule.length ? sortRule : [
{name: "sort", type: "asc"},
{name: "_add_time", type: "desc"},
],
});
for (let i = 0; i < res.rows.length; i++) {
if (res.rows[i].companyId) {
res.rows[i].company = await vk.baseDao.findByWhereJson({
dbName: 'uni-id-users',
whereJson: {
_id: res.rows[i].companyId
},
});
}
}
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/update 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.updateById({
dbName: 'jjx-album',
dataJson: data,
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.add({
dbName: 'jjx-article-category',
dataJson: data
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/delete 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { uid } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.deleteById({
dbName: 'jjx-article-category',
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,28 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/list 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { uid } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
res = await vk.baseDao.getTableData({
dbName: 'jjx-article-category',
sortArr: [
{ name: "sort", type: "asc" },
{ name: "_id", type: "desc" },
],
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,26 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/update 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.updateById({
dbName: 'jjx-article-category',
dataJson: data,
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,30 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.add({
dbName: 'jjx-article',
dataJson: {
...data, ...{
viewNum: 0,
downloadNum: 0,
}
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/delete 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { uid } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.deleteById({
dbName: 'jjx-article',
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,37 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/list 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid, pageIndex, pageSize, sortRule} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
res = await vk.baseDao.selects({
dbName: 'jjx-article',
pageIndex,
pageSize,
getCount: true,
sortArr: sortRule && sortRule.length ? sortRule : [{"name": "_add_time", "type": "desc"}]
});
for (let i = 0; i < res.rows.length; i++) {
if (res.rows[i].parentId) {
res.rows[i].category = await vk.baseDao.findById({
dbName: "jjx-article-category",
id: res.rows[i].parentId
})
}
}
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,26 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/update 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.updateById({
dbName: 'jjx-article',
dataJson: data,
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,90 @@
'use strict';
const normalizeSortRule = require('../../utils/sortRule.js');
module.exports = {
/**
* XXXnameXXX
* @url admin/old/sys/getList 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { pageIndex, pageSize, formData, sortRule } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
const whereJson = {}
if (vk.pubfn.isNotNull(formData)) {
if (vk.pubfn.isNotNull(formData.transactionId)) whereJson.transactionId = new RegExp(formData.transactionId)
if (vk.pubfn.isNotNull(formData.type)) whereJson.type = formData.type
if (vk.pubfn.isNotNull(formData.status)) whereJson.status = formData.status
}
res = await vk.baseDao.selects({
dbName: "jjx-contract",
getCount: true,
pageIndex,
pageSize,
whereJson,
sortArr: normalizeSortRule(sortRule, [{"name": "_add_time", "type":"desc" }], ["_add_time"]),
foreignDB: [
{
dbName: "uni-id-users",
localKey: "userId",
foreignKey: "_id",
as: "user",
limit: 1, // limit=1则以对象形式返回
fieldJson: {
_id: true,
company: {
companyName: true
},
person: {
personName: true
},
businessCard: true,
accountType: true,
},
},
{
dbName: "jjx-user-contract",
localKey: "_id",
foreignKey: "contractId",
as: "userContract",
limit: 500, // limit=1则以对象形式返回
foreignDB: [
{
dbName: "uni-id-users",
localKey: "userId",
foreignKey: "_id",
as: "user",
limit: 1, // limit=1则以对象形式返回
fieldJson: {
_id: true,
company: {
companyName: true,
mobile: true,
},
person: {
personName: true,
mobile: true,
},
businessCard: true,
accountType: true,
mobile: true,
},
}
]
},
]
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,34 @@
module.exports = {
/**
* 添加单条数据
* @url admin/kong/sys/add 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: 'ok'};
// 业务逻辑开始-----------------------------------------------------------
let {
name,
field,
isOn,
} = data;
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-contract-template";
res.id = await vk.baseDao.add({
dbName,
dataJson: {
name,
field,
isOn,
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,39 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/old/sys/changeField 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.updateById({
dbName: "jjx-contract-template",
id: data.id,
dataJson: {
[data.field]: data.value
}
});
if (data.field === "isOn" && data.value) {
await vk.baseDao.update({
dbName: "jjx-contract-template",
whereJson: {
_id: _.neq(data.id),
},
dataJson: {
"isOn": 0
}
});
}
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,30 @@
module.exports = {
/**
* 数据删除
* @url admin/kong/sys/delete 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let { _id } = data;
if(vk.pubfn.isNull(_id)){
return { code : -1, msg : 'id不能为空' };
}
let dbName = "jjx-contract-template";
await vk.baseDao.deleteById({
dbName: dbName,
id:_id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,29 @@
module.exports = {
/**
* 查询多条记录 分页
* @url admin/kong/sys/getList 前端调用的url参数地址
* data 请求参数 说明
* @param {Number} pageIndex 当前页码
* @param {Number} pageSize 每页显示数量
* @param {Array<Object>} sortRule 排序规则
* @param {object} formData 查询条件数据源
* @param {Array<Object>} columns 查询条件规则
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : '' };
// 业务逻辑开始-----------------------------------------------------------
let dbName = "jjx-contract-template";
res = await vk.baseDao.getTableData({
dbName,
data
});
return res;
}
}
@@ -0,0 +1,40 @@
module.exports = {
/**
* 修改数据
* @url admin/kong/sys/update 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: 'ok'};
// 业务逻辑开始-----------------------------------------------------------
let {
_id,
name,
field,
isOn,
} = data;
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
if (vk.pubfn.isNullOne(_id)) {
return {code: -1, msg: '参数错误'};
}
let dbName = "jjx-contract-template";
await vk.baseDao.updateById({
dbName,
id: _id,
dataJson: {
name,
field,
isOn,
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,84 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/old/sys/changeField 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const dataJson = {
[data.field]: data.value
}
if (data.field === 'paidConfirm') {
dataJson.status = 1
const certificate = await vk.baseDao.findById({
dbName: "jjx-certificate",
id: data.id
});
const contract = await vk.baseDao.findById({
dbName: "jjx-contract",
id: certificate.contractId
});
const canDownloadUidList = []
if (!contract.canDownloadUidList) {
canDownloadUidList.push(certificate.uid)
} else {
canDownloadUidList.push(...contract.canDownloadUidList, certificate.uid)
}
await vk.baseDao.updateById({
dbName: "jjx-contract",
id: certificate.contractId,
dataJson: {
canDownloadUidList
}
});
const amount = certificate.amount
const orderId = await vk.baseDao.add({
dbName: "jjx-order",
dataJson: {
orderNo: vk.pubfn.createOrderNo("39XU", 20),
uid: certificate.uid,
orderStatus: 4,
type: 12,
amount,
offAmount: amount,
saveAmount: amount,
offRate: 100,
isInvoice: 1,
name: certificate.invoice.companyName,
code: certificate.invoice.taxNumber,
phone: certificate.invoice.phone,
bankAccount: certificate.invoice.bankAccount,
bankName: certificate.invoice.bankName,
}
})
await vk.baseDao.add({
dbName: "jjx-order-goods",
dataJson: {
orderId,
goodsId: certificate.contractId,
num: 1,
goodsName: `合同:${contract.transactionId}司法调证`,
goodsPrice: amount,
goodsCover: null,
}
})
}
await vk.baseDao.updateById({
dbName: "jjx-certificate",
id: data.id,
dataJson
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,60 @@
'use strict';
const normalizeSortRule = require('../../utils/sortRule.js');
module.exports = {
/**
* XXXnameXXX
* @url admin/old/sys/getList 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {pageIndex, pageSize, formData, sortRule} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const whereJson = {}
res = await vk.baseDao.selects({
dbName: "jjx-certificate",
getCount: true,
pageIndex,
pageSize,
whereJson,
sortArr: normalizeSortRule(sortRule, [{"name": "_add_time", "type":"desc"}], ["_add_time"]),
foreignDB: [
{
dbName: "uni-id-users",
localKey: "userId",
foreignKey: "_id",
as: "user",
limit: 1, // limit=1则以对象形式返回
fieldJson: {
_id: true,
company: {
companyName: true
},
person: {
personName: true
},
businessCard: true,
accountType: true,
},
},
{
dbName: "jjx-contract",
localKey: "contractId",
foreignKey: "_id",
as: "contract",
limit: 1, // limit=1则以对象形式返
},
]
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,34 @@
module.exports = {
/**
* 添加单条数据
* @url admin/kong/sys/add 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: 'ok'};
// 业务逻辑开始-----------------------------------------------------------
let {
name,
field,
isOn,
} = data;
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-contract-template";
res.id = await vk.baseDao.add({
dbName,
dataJson: {
name,
field,
isOn,
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,39 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/old/sys/changeField 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.updateById({
dbName: "jjx-contract-template",
id: data.id,
dataJson: {
[data.field]: data.value
}
});
if (data.field === "isOn" && data.value) {
await vk.baseDao.update({
dbName: "jjx-contract-template",
whereJson: {
_id: _.neq(data.id),
},
dataJson: {
"isOn": 0
}
});
}
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,30 @@
module.exports = {
/**
* 数据删除
* @url admin/kong/sys/delete 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let { _id } = data;
if(vk.pubfn.isNull(_id)){
return { code : -1, msg : 'id不能为空' };
}
let dbName = "jjx-contract-template";
await vk.baseDao.deleteById({
dbName: dbName,
id:_id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,29 @@
module.exports = {
/**
* 查询多条记录 分页
* @url admin/kong/sys/getList 前端调用的url参数地址
* data 请求参数 说明
* @param {Number} pageIndex 当前页码
* @param {Number} pageSize 每页显示数量
* @param {Array<Object>} sortRule 排序规则
* @param {object} formData 查询条件数据源
* @param {Array<Object>} columns 查询条件规则
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : '' };
// 业务逻辑开始-----------------------------------------------------------
let dbName = "jjx-contract-template";
res = await vk.baseDao.getTableData({
dbName,
data
});
return res;
}
}
@@ -0,0 +1,40 @@
module.exports = {
/**
* 修改数据
* @url admin/kong/sys/update 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: 'ok'};
// 业务逻辑开始-----------------------------------------------------------
let {
_id,
name,
field,
isOn,
} = data;
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
if (vk.pubfn.isNullOne(_id)) {
return {code: -1, msg: '参数错误'};
}
let dbName = "jjx-contract-template";
await vk.baseDao.updateById({
dbName,
id: _id,
dataJson: {
name,
field,
isOn,
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/coopExplore/config/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.add({
dbName: 'jjx-coop-config',
dataJson: data
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/coopExplore/config/sys/delete 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { uid } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.deleteById({
dbName: 'jjx-coop-config',
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,28 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/coopExplore/config/sys/list 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { uid } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
res = await vk.baseDao.getTableData({
dbName: 'jjx-coop-config',
sortArr: [
{ name: "sort", type: "asc" },
{ name: "_add_time", type: "desc" },
],
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,26 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/coopExplore/config/sys/update 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.updateById({
dbName: 'jjx-coop-config',
dataJson: data,
id: data._id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.add({
dbName: 'jjx-dict',
dataJson: data
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,28 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/list 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid, pageIndex, pageSize} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
res = await vk.baseDao.select({
dbName: 'jjx-dict',
getCount: true,
pageIndex,
pageSize,
sortArr: [{"name": "_add_time", "type": "desc"}],
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,46 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/update 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
await vk.baseDao.updateById({
dbName: 'jjx-dict',
dataJson: {
content: data.content,
name: data.name,
},
id: data._id
});
console.log('id', data._id, data._id === '657d36befe975f63af1f24e7')
if (data._id === '657d36befe975f63af1f24e7') {
const template_id = vk.pubfn.createOrderNo("CT", 20)
const uploaddocs = await pubFun.fadada('uploadtemplate.api', {
template_id,
doc_url: data.content,
})
console.log('uploaddocs', uploaddocs)
await vk.baseDao.updateById({
dbName: 'jjx-dict',
dataJson: {
content: template_id
},
id: "80e3bed065a5560e075799d24532b14f"
});
}
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,35 @@
'use strict';
module.exports = {
/**
* 新增询价模板
* @url admin/enquiry/template/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let {
label,
enable,
sort,
values
} = data;
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-enquiry-attributes";
res.id = await vk.baseDao.add({
dbName,
dataJson:{
label,
enable,
sort,
values
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,29 @@
module.exports = {
/**
* 数据删除
* @url admin/kong/sys/delete 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let { _id } = data;
if(vk.pubfn.isNull(_id)){
return { code : -1, msg : 'id不能为空' };
}
let dbName = "jjx-enquiry-attributes";
await vk.baseDao.deleteById({
dbName,
id:_id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,29 @@
module.exports = {
/**
* 查询多条记录 分页
* @url admin/kong/sys/getList 前端调用的url参数地址
* data 请求参数 说明
* @param {Number} pageIndex 当前页码
* @param {Number} pageSize 每页显示数量
* @param {Array<Object>} sortRule 排序规则
* @param {object} formData 查询条件数据源
* @param {Array<Object>} columns 查询条件规则
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : '' };
// 业务逻辑开始-----------------------------------------------------------
let dbName = "jjx-enquiry-attributes";
res = await vk.baseDao.getTableData({
dbName,
data
});
return res;
}
}
@@ -0,0 +1,37 @@
'use strict';
module.exports = {
/**
* 新增询价模板
* @url admin/enquiry/template/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let {
_id,
label,
enable,
sort,
values
} = data;
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-enquiry-attributes";
res.id = await vk.baseDao.updateById({
dbName,
id: _id,
dataJson:{
label,
enable,
sort,
values
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,24 @@
'use strict';
module.exports = {
/**
* 新增询价模板
* @url admin/enquiry/template/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-enquiry-package";
res.id = await vk.baseDao.add({
dbName,
dataJson: data
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,29 @@
module.exports = {
/**
* 数据删除
* @url admin/kong/sys/delete 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let { _id } = data;
if(vk.pubfn.isNull(_id)){
return { code : -1, msg : 'id不能为空' };
}
let dbName = "jjx-enquiry-package";
await vk.baseDao.deleteById({
dbName,
id:_id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,32 @@
module.exports = {
/**
* 查询多条记录 分页
* @url admin/kong/sys/getList 前端调用的url参数地址
* data 请求参数 说明
* @param {Number} pageIndex 当前页码
* @param {Number} pageSize 每页显示数量
* @param {Array<Object>} sortRule 排序规则
* @param {object} formData 查询条件数据源
* @param {Array<Object>} columns 查询条件规则
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid, pageIndex, pageSize} = data;
let res = {code: 0, msg: ''};
// 业务逻辑开始-----------------------------------------------------------
let dbName = "jjx-enquiry-package";
res = await vk.baseDao.selects({
dbName,
pageIndex,
pageSize,
getCount: true,
sortArr: [{"name": "sort", "type": "asc"}],
});
return res;
}
}
@@ -0,0 +1,25 @@
'use strict';
module.exports = {
/**
* 新增询价模板
* @url admin/enquiry/template/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-enquiry-package";
res.id = await vk.baseDao.updateById({
dbName,
id: _id,
dataJson: data
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,31 @@
module.exports = {
/**
* 查询多条记录 分页
* @url admin/kong/sys/getList 前端调用的url参数地址
* data 请求参数 说明
* @param {Number} pageIndex 当前页码
* @param {Number} pageSize 每页显示数量
* @param {Array<Object>} sortRule 排序规则
* @param {object} formData 查询条件数据源
* @param {Array<Object>} columns 查询条件规则
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid, sheetId} = data;
let res = {code: 0, msg: ''};
// 业务逻辑开始-----------------------------------------------------------
let dbName = "jjx-enquiry-quote";
res = await vk.baseDao.selects({
dbName,
whereJson: {
sheetId
}
});
return res;
}
}
@@ -0,0 +1,99 @@
'use strict';
const dayjs = require("dayjs");
var isBetween = require('dayjs/plugin/isBetween')
dayjs.extend(isBetween)
module.exports = {
/**
* XXXnameXXX
* @url admin/old/sys/changeField 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const sheet = await vk.baseDao.findByWhereJson({
dbName: "jjx-enquiry-sheet",
whereJson: {
_id: data.id
},
})
if (data.field === 'isShow' && data.value === 1) {
const messageUserList = await vk.baseDao.select({
dbName: "jjx-message-config",
whereJson: {
enquiry: true,
productList: _.in(sheet.productList.map(item => item.goodsName))
}
})
const messageList = []
const messageTitle = sheet.productList.map(item => `${item.goodsName}${item.materialQuality ? `(${item.materialQuality})` : ''}`).join("/")
for (let i = 0; i < messageUserList.rows.length; i++) {
const config = messageUserList.rows[i]
const date = dayjs().format("YYYY-MM-DD")
// if (config.doNotDisturbRange && config.doNotDisturbRange[0]) {
// const doNotDisturbRangeStart = dayjs(config.doNotDisturbRange[0]).format("HH:mm")
// const doNotDisturbRangeEnd = dayjs(config.doNotDisturbRange[1]).format("HH:mm")
// if (dayjs().isBetween(dayjs(`${date} ${doNotDisturbRangeStart}`), dayjs(`${date} ${doNotDisturbRangeEnd}`)))
// continue
// }
if (config.doNotDisturbStart && config.doNotDisturbStart.length) {
const doNotDisturbRangeStart = dayjs(`${date} ${config.doNotDisturbStart[0]}:${config.doNotDisturbStart[1]}`).format("HH:mm")
const doNotDisturbRangeEnd = dayjs(`${date} ${config.doNotDisturbEnd[0]}:${config.doNotDisturbEnd[1]}`).format("HH:mm")
if (dayjs().isBetween(dayjs(`${date} ${doNotDisturbRangeStart}`), dayjs(`${date} ${doNotDisturbRangeEnd}`)))
continue
}
let inAddress = false
if (config.addressList && config.addressList.length > 0) {
for (let j = 0; j < config.addressList.length; j++) {
if (config.addressList[j].province.code === sheet.addressRegion.province.code) {
if (config.addressList[j].city === null) inAddress = true
else if (config.addressList[j].city.code === sheet.addressRegion.city.code) {
if (config.addressList[j].area === null) inAddress = true
else if (config.addressList[j].area.code === sheet.addressRegion.area.code) {
inAddress = true
}
}
}
}
} else inAddress = true
if (!inAddress) continue
if (!config.tradeSelf && sheet.tradeMethod === 0) continue
if (!config.tradePlatform && sheet.tradeMethod === 1) continue
if (messageUserList.rows[i].uid !== sheet.uid) {
messageList.push({
uid: messageUserList.rows[i].uid,
title: `找买家:${messageTitle}`,
content: `新的找买家信息发布,赶紧去看看吧`,
type: 'enquiry',
hasRead: false,
pk: res.id
})
await pubFun.sendNotifySms(messageUserList.rows[i].uid, 'SMS_474510001')
}
}
if (messageList.length > 0) {
await vk.baseDao.adds({
dbName: "jjx-message",
dataJson: messageList
});
}
}
await vk.baseDao.updateById({
dbName: "jjx-enquiry-sheet",
id: data.id,
dataJson: {
[data.field]: data.value
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,103 @@
'use strict';
const normalizeSortRule = require('../../utils/sortRule.js');
const DEFAULT_NOTARY_SERVICE_RATE = 0.1;
module.exports = {
/**
* XXXnameXXX
* @url admin/old/sys/getList 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {pageIndex, pageSize, formData, sortRule} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const whereJson = {};
if (vk.pubfn.isNotNull(formData)) {
if (vk.pubfn.isNotNull(formData.title)) whereJson.title = new RegExp(formData.title);
if (vk.pubfn.isNotNull(formData.status)) whereJson.status = formData.status;
if (vk.pubfn.isNotNull(formData.signMethod)) whereJson.signMethod = formData.signMethod;
}
// 区域限制
if (userInfo.allowArea && userInfo.allowArea.length > 0) {
whereJson['addressRegion.city.code'] = _.in(userInfo.allowArea.map(item => item.area.city.code));
}
console.log('whereJson', whereJson)
res = await vk.baseDao.selects({
dbName: "jjx-enquiry-sheet",
getCount: true,
pageIndex,
pageSize,
whereJson,
sortArr: normalizeSortRule(sortRule, [{"name": "_add_time", "type": "desc"}], ["_add_time"]),
foreignDB: [
{
dbName: "uni-id-users",
localKey: "userId",
foreignKey: "_id",
as: "user",
limit: 1, // limit=1则以对象形式返回
fieldJson: {
_id: true,
company: {
companyName: true
},
person: {
personName: true
},
businessCard: true,
accountType: true,
},
},
{
dbName: "jjx-enquiry-quote",
localKey: "_id",
foreignKey: "sheetId",
as: "quoteList",
limit: 500, // limit=1则以对象形式返回
},
]
});
for (let i = 0; i < res.rows.length; i++) {
if (res.rows[i].tradeMethod === 1 && (res.rows[i].notaryServiceRate === undefined || res.rows[i].notaryServiceRate === null || res.rows[i].notaryServiceRate === '')) {
res.rows[i].notaryServiceRate = DEFAULT_NOTARY_SERVICE_RATE
}
const order = await vk.baseDao.findByWhereJson({
dbName: 'jjx-order',
whereJson: {
sheetId: res.rows[i]._id
}
})
if (order) {
res.rows[i].order = order
const payList = await vk.baseDao.select({
dbName: 'jjx-order-pay-list',
whereJson: {
orderId: order._id
}
})
res.rows[i].payList = null
if (payList) {
res.rows[i].payList = payList.rows
}
}
res.rows[i].contract = await vk.baseDao.findByWhereJson({
dbName: 'jjx-contract',
whereJson: {
sheetId: res.rows[i]._id
}
})
}
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,37 @@
'use strict';
module.exports = {
/**
* 新增询价模板
* @url admin/enquiry/template/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let {
name,
enable,
sort,
attributes,
extraAttributes
} = data;
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-enquiry-template";
res.id = await vk.baseDao.add({
dbName,
dataJson:{
name,
enable,
sort,
attributes,
extraAttributes
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,29 @@
module.exports = {
/**
* 数据删除
* @url admin/kong/sys/delete 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let { _id } = data;
if(vk.pubfn.isNull(_id)){
return { code : -1, msg : 'id不能为空' };
}
let dbName = "jjx-enquiry-template";
await vk.baseDao.deleteById({
dbName,
id:_id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,30 @@
module.exports = {
/**
* 查询多条记录 分页
* @url admin/kong/sys/getList 前端调用的url参数地址
* data 请求参数 说明
* @param {Number} pageIndex 当前页码
* @param {Number} pageSize 每页显示数量
* @param {Array<Object>} sortRule 排序规则
* @param {object} formData 查询条件数据源
* @param {Array<Object>} columns 查询条件规则
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : '' };
// 业务逻辑开始-----------------------------------------------------------
let dbName = "jjx-enquiry-template";
res = await vk.baseDao.getTableData({
dbName,
data,
sortArr: [{"name": "sort", "type": "asc"}, {"name": "_add_time", "type": "desc"}],
});
return res;
}
}
@@ -0,0 +1,39 @@
'use strict';
module.exports = {
/**
* 新增询价模板
* @url admin/enquiry/template/sys/add 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let {
_id,
name,
enable,
sort,
attributes,
extraAttributes
} = data;
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-enquiry-template";
res.id = await vk.baseDao.updateById({
dbName,
id: _id,
dataJson:{
name,
enable,
sort,
attributes,
extraAttributes
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,30 @@
module.exports = {
/**
* 添加单条数据
* @url admin/kong/sys/add 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: 'ok'};
// 业务逻辑开始-----------------------------------------------------------
let dbName = "jjx-ensure-config";
res.id = await vk.baseDao.add({
dbName,
dataJson: {
...data
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,29 @@
module.exports = {
/**
* 数据删除
* @url admin/kong/sys/delete 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
let { _id } = data;
if(vk.pubfn.isNull(_id)){
return { code : -1, msg : 'id不能为空' };
}
let dbName = "jjx-ensure-config";
await vk.baseDao.deleteById({
dbName,
id:_id
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,27 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/old/sys/getList 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { pageIndex, pageSize } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
res = await vk.baseDao.selects({
dbName: "jjx-ensure-config",
pageIndex,
pageSize,
getCount: true,
sortArr: [{"name": "sort", "type":"asc" }, {"name": "_add_time", "type":"desc" }],
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,31 @@
module.exports = {
/**
* 修改数据
* @url admin/kong/sys/update 前端调用的url参数地址
* data 请求参数 说明
* res 返回参数说明
* @param {Number} code 错误码,0表示成功
* @param {String} msg 详细信息
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk , db, _ } = util;
let { uid } = data;
let res = { code : 0, msg : 'ok' };
// 业务逻辑开始-----------------------------------------------------------
// 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段
let dbName = "jjx-ensure-config";
await vk.baseDao.updateById({
dbName,
id: data._id,
dataJson:{
...data
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,28 @@
'use strict';
module.exports = {
/**
* 认证审核
* @url admin/system/user/sys/changeStatus 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const {id, field, value} = data
const dataJson = {}
dataJson[field] = value
const factoryData = await vk.baseDao.updateAndReturn({
dbName: 'jjx-factory',
whereJson: {
_id: id
},
dataJson
})
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,38 @@
'use strict';
module.exports = {
/**
* 认证审核
* @url admin/system/user/sys/changeStatus 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const {id, status, refuseReason} = data
const factoryData = await vk.baseDao.updateAndReturn({
dbName: 'jjx-factory',
whereJson: {
_id: id
},
dataJson: {
status,
refuseReason,
isShow: status === 1
}
})
await vk.baseDao.updateById({
dbName: "uni-id-users",
id: factoryData.uid,
dataJson: {
factoryStatus: status
}
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,43 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/article/category/sys/list 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid, pageIndex, pageSize, formData, sortRule} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const whereJson = {};
if (vk.pubfn.isNotNull(formData.keyword)) {
whereJson['user.nickname'] = new RegExp(formData.keyword);
}
res = await vk.baseDao.selects({
dbName: 'jjx-factory',
pageIndex,
pageSize,
whereJson,
getCount: true,
sortArr: sortRule && sortRule.length ? sortRule : [{"name": "_add_time", "type": "desc"}],
foreignDB: [
{
dbName: "uni-id-users",
localKey: "uid",
foreignKey: "_id",
as: "user",
limit: 1,
},
]
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,38 @@
'use strict';
module.exports = {
/**
* XXXnameXXX
* @url admin/fadada/sys/getList 前端调用的url参数地址
* data 请求参数
* @param {String} params1 参数1
*/
main: async (event) => {
let {data = {}, userInfo, util, filterResponse, originalParam} = event;
let {customUtil, uniID, config, pubFun, vk, db, _} = util;
let {uid} = data;
let res = {code: 0, msg: ""};
// 业务逻辑开始-----------------------------------------------------------
const dbName = "fadada-verify-record";
res = await vk.baseDao.selects({
dbName,
getCount: true,
whereJson: {
type: data.type
},
sortArr: [{name: "authenticationSubmitTime", type: "desc"}],
foreignDB: [
{
dbName: "uni-id-users",
localKey: "_id",
foreignKey: "_id",
as: "user",
limit: 1, // limit=1则以对象形式返回
}
]
});
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
@@ -0,0 +1,56 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 新增资金流水
* @url admin/finance/balance/sys/add 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, userInfo, util } = event;
let { vk } = util;
const transaction = await vk.baseDao.startTransaction();
try {
const description = String(data.description || '').trim();
if (!description) {
throw new Error('说明不能为空');
}
const logData = {
description,
amount: balanceUtil.normalizeAmount(data.amount),
type: balanceUtil.normalizeType(data.type),
logTime: balanceUtil.normalizeTime(data.logTime),
operatorId: userInfo && userInfo.uid ? userInfo.uid : '',
source: data.source || 'manual'
};
const changeAmount = balanceUtil.buildBalanceChange(logData);
await balanceUtil.checkBalanceAvailable({
transaction,
vk,
changeAmount
});
const addRes = await vk.baseDao.add({
db: transaction,
dbName: 'jjx-balance-log',
dataJson: logData
});
await balanceUtil.updateBalanceWithDelta({
transaction,
vk,
delta: changeAmount,
lastLogId: addRes.id
});
await transaction.commit();
return { code: 0, msg: '' };
} catch (err) {
return await balanceUtil.rollbackTransaction({
transaction,
err
});
}
}
};
@@ -0,0 +1,57 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 删除资金流水
* @url admin/finance/balance/sys/delete 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk } = util;
const transaction = await vk.baseDao.startTransaction();
try {
if (vk.pubfn.isNull(data._id)) {
throw new Error('流水ID不能为空');
}
const oldLog = await vk.baseDao.findByWhereJson({
db: transaction,
dbName: 'jjx-balance-log',
whereJson: {
_id: data._id
}
});
if (!oldLog) {
throw new Error('流水不存在');
}
const revertDelta = Number((-balanceUtil.buildBalanceChange(oldLog)).toFixed(2));
await balanceUtil.checkBalanceAvailable({
transaction,
vk,
changeAmount: revertDelta
});
await vk.baseDao.deleteById({
db: transaction,
dbName: 'jjx-balance-log',
id: data._id
});
await balanceUtil.updateBalanceWithDelta({
transaction,
vk,
delta: revertDelta
});
await transaction.commit();
return { code: 0, msg: '' };
} catch (err) {
return await balanceUtil.rollbackTransaction({
transaction,
err
});
}
}
};
@@ -0,0 +1,91 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 查询状态
* @url admin/finance/balance/sys/getActionLog 前端调用的url参数地址
* @param {String} accNo 账号
* @param {String} reqDate 请求日期,格式:yyyyMMdd
* @param {String} reqJournalNo 请求流水号
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk } = util;
let { accNo, reqDate, reqJournalNo } = data;
accNo = String(accNo || '').trim();
reqDate = String(reqDate || '').trim();
reqJournalNo = String(reqJournalNo || '').trim();
if (!accNo) {
return {
code: -1,
msg: 'accNo不能为空'
};
}
if (!reqDate) {
return {
code: -1,
msg: 'reqDate不能为空'
};
}
if (!/^\d{8}$/.test(reqDate)) {
return {
code: -1,
msg: 'reqDate格式不正确'
};
}
if (!reqJournalNo) {
return {
code: -1,
msg: 'reqJournalNo不能为空'
};
}
let res = await vk.request({
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/getActionLog',
method: 'POST',
dataType: 'json',
header: {
'content-type': 'application/json; charset=utf-8'
},
data: {
accNo,
reqDate,
reqJournalNo
},
timeout: 60000
});
if (res && typeof res === 'object' && typeof res.code === 'undefined') {
res.code = 0;
}
const responseObjects = balanceUtil.getRemoteResponseObjects(res);
const list = balanceUtil.pickFirstDefined([
Array.isArray(res.list) ? res.list : undefined,
Array.isArray(res.rows) ? res.rows : undefined,
Array.isArray(res.data) ? res.data : undefined,
Array.isArray(res.data && res.data.list) ? res.data.list : undefined,
Array.isArray(res.data && res.data.rows) ? res.data.rows : undefined,
Array.isArray(res.info && res.info.list) ? res.info.list : undefined,
Array.isArray(res.info && res.info.rows) ? res.info.rows : undefined,
Array.isArray(res.content && res.content.list) ? res.content.list : undefined,
Array.isArray(res.content && res.content.rows) ? res.content.rows : undefined
]) || [];
if (responseObjects.data && typeof responseObjects.data === 'object' && !Array.isArray(responseObjects.data)) {
responseObjects.data.list = list;
} else if (res && typeof res === 'object') {
res.data = {
list
};
}
return res;
}
};
@@ -0,0 +1,81 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 查询余额明细
* @url admin/finance/balance/sys/getFlow 前端调用的url参数地址
* @param {String} accNo 账号
* @param {String} transDate 交易日期,格式:yyyyMMdd
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk } = util;
let { accNo, transDate } = data;
accNo = String(accNo || '').trim();
transDate = String(transDate || '').trim();
if (!accNo) {
return {
code: -1,
msg: 'accNo不能为空'
};
}
if (!transDate) {
return {
code: -1,
msg: 'transDate不能为空'
};
}
if (!/^\d{8}$/.test(transDate)) {
return {
code: -1,
msg: 'transDate格式不正确'
};
}
let res = await vk.request({
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/getFlow',
method: 'POST',
dataType: 'json',
header: {
'content-type': 'application/json; charset=utf-8'
},
data: {
accNo,
transDate
},
timeout: 60000
});
if (res && typeof res === 'object' && typeof res.code === 'undefined') {
res.code = 0;
}
const responseObjects = balanceUtil.getRemoteResponseObjects(res);
const list = balanceUtil.pickFirstDefined([
Array.isArray(res.list) ? res.list : undefined,
Array.isArray(res.rows) ? res.rows : undefined,
Array.isArray(res.data) ? res.data : undefined,
Array.isArray(res.data && res.data.list) ? res.data.list : undefined,
Array.isArray(res.data && res.data.rows) ? res.data.rows : undefined,
Array.isArray(res.info && res.info.list) ? res.info.list : undefined,
Array.isArray(res.info && res.info.rows) ? res.info.rows : undefined,
Array.isArray(res.content && res.content.list) ? res.content.list : undefined,
Array.isArray(res.content && res.content.rows) ? res.content.rows : undefined
]) || [];
if (responseObjects.data && typeof responseObjects.data === 'object' && !Array.isArray(responseObjects.data)) {
responseObjects.data.list = list;
} else if (res && typeof res === 'object') {
res.data = {
list
};
}
return res;
}
};
@@ -0,0 +1,63 @@
'use strict';
const dayjs = require('dayjs');
const balanceUtil = require('./util.js');
module.exports = {
/**
* 查询余额
* @url admin/finance/balance/sys/getInfo 前端调用的url参数地址
* @param {String} accNo 账号
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk } = util;
let { accNo } = data;
accNo = String(accNo || '').trim();
if (!accNo) {
return {
code: -1,
msg: 'accNo不能为空'
};
}
let res = await balanceUtil.requestMerchantBalance({
vk,
accNo
});
if (res && typeof res === 'object' && typeof res.code === 'undefined') {
res.code = 0;
}
const merchantBalance = balanceUtil.getRemoteMerchantBalance(res);
if (merchantBalance !== null) {
const updateTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
const syncRes = await balanceUtil.syncMerchantBalance({
vk,
accNo,
merchantBalance,
updateTime
});
const nextMerchantBalance = syncRes.merchantBalance;
if (res.data && typeof res.data === 'object') {
res.data.balance = nextMerchantBalance;
res.data.updateTime = updateTime;
} else if (res.info && typeof res.info === 'object') {
res.info.balance = nextMerchantBalance;
res.info.updateTime = updateTime;
} else if (res.content && typeof res.content === 'object') {
res.content.balance = nextMerchantBalance;
res.content.updateTime = updateTime;
} else {
res.data = {
balance: nextMerchantBalance,
updateTime
};
}
}
return res;
}
};
@@ -0,0 +1,53 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 资金流水列表
* @url admin/finance/balance/sys/getList 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk, _ } = util;
let { pageIndex, pageSize, formData = {} } = data;
let res = { code: 0, msg: '' };
const andArr = [];
if (vk.pubfn.isNotNull(formData.type)) {
andArr.push({ type: formData.type });
}
if (vk.pubfn.isNotNull(formData.logTime) && Array.isArray(formData.logTime) && formData.logTime.length === 2) {
andArr.push({
logTime: _.gte(Number(formData.logTime[0]))
});
andArr.push({
logTime: _.lte(Number(formData.logTime[1]))
});
}
let whereJson = {};
if (andArr.length > 0) {
whereJson = _.and(andArr);
}
res = await vk.baseDao.selects({
dbName: 'jjx-balance-log',
getCount: true,
pageIndex,
pageSize,
whereJson,
sortArr: [{ name: 'logTime', type: 'desc' }, { name: '_add_time', type: 'desc' }]
});
res.rows = res.rows.map(item => ({
...item,
amount: balanceUtil.normalizeAmount(item.amount),
merchantId: item.merchantId || '',
merchantName: item.merchantName || '',
srcReqId: item.srcReqId || '',
status: typeof item.status === 'number' ? item.status : Number(item.status || 0)
}));
return res;
}
};
@@ -0,0 +1,39 @@
'use strict';
const { BALANCE_DOC_ID, getBalanceInfoList } = require('./util.js');
module.exports = {
/**
* 资金汇总
* @url admin/finance/balance/sys/getSummary 前端调用的url参数地址
*/
main: async (event) => {
let { util } = event;
let { vk } = util;
let info = await vk.baseDao.findByWhereJson({
dbName: 'jjx-balance',
whereJson: {
_id: BALANCE_DOC_ID
}
});
if (!info) {
return {
code: -1,
msg: `jjx-balance余额记录不存在: ${BALANCE_DOC_ID}`
};
}
const balanceInfoList = getBalanceInfoList(info.balanceInfo || {});
return {
code: 0,
msg: '',
data: {
balance: Number(Number(info.balance || 0).toFixed(2)),
updateTime: info.updateTime || info._update_time_str || info._add_time_str || '',
balanceInfoList
}
};
}
};
@@ -0,0 +1,75 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 编辑资金流水
* @url admin/finance/balance/sys/update 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, userInfo, util } = event;
let { vk } = util;
const transaction = await vk.baseDao.startTransaction();
try {
if (vk.pubfn.isNull(data._id)) {
throw new Error('流水ID不能为空');
}
const oldLog = await vk.baseDao.findByWhereJson({
db: transaction,
dbName: 'jjx-balance-log',
whereJson: {
_id: data._id
}
});
if (!oldLog) {
throw new Error('流水不存在');
}
const description = String(data.description || '').trim();
if (!description) {
throw new Error('说明不能为空');
}
const newLog = {
description,
amount: balanceUtil.normalizeAmount(data.amount),
type: balanceUtil.normalizeType(data.type),
logTime: balanceUtil.normalizeTime(data.logTime),
operatorId: userInfo && userInfo.uid ? userInfo.uid : oldLog.operatorId || '',
source: oldLog.source || data.source || 'manual'
};
const oldChange = balanceUtil.buildBalanceChange(oldLog);
const newChange = balanceUtil.buildBalanceChange(newLog);
const delta = Number((newChange - oldChange).toFixed(2));
await balanceUtil.checkBalanceAvailable({
transaction,
vk,
changeAmount: delta
});
await vk.baseDao.updateById({
db: transaction,
dbName: 'jjx-balance-log',
id: data._id,
dataJson: newLog
});
await balanceUtil.updateBalanceWithDelta({
transaction,
vk,
delta,
lastLogId: data._id
});
await transaction.commit();
return { code: 0, msg: '' };
} catch (err) {
return await balanceUtil.rollbackTransaction({
transaction,
err
});
}
}
};
@@ -0,0 +1,381 @@
'use strict';
const dayjs = require('dayjs');
const BALANCE_DOC_ID = 'e35392d069f2104f003790b271c67c6d';
const MERCHANT_OPTIONS = [
{ accNo: 'zg000002466577', label: '广西金久信电子商务有限公司' },
{ accNo: 'zg000002460927', label: '南宁亿利通钢管有限公司' },
{ accNo: 'zg000002494918', label: '广西冀旺贸易有限公司' },
{ accNo: 'zg000002459804', label: '广西金久信电子商务有限公司' }
];
const MERCHANT_MAP = MERCHANT_OPTIONS.reduce((map, item) => {
map[item.accNo] = item.label;
return map;
}, {});
function normalizeAmount(value) {
const amount = Number(value || 0);
if (!Number.isFinite(amount)) {
throw new Error('金额格式不正确');
}
return Number(amount.toFixed(2));
}
function normalizeFenToYuan(value) {
const amount = Number(value || 0);
if (!Number.isFinite(amount)) {
throw new Error('金额格式不正确');
}
return Number((amount / 100).toFixed(2));
}
function normalizeType(type) {
if (!['income', 'expense'].includes(type)) {
throw new Error('类型不正确');
}
return type;
}
function normalizeTime(value) {
const time = Number(value || Date.now());
if (!Number.isFinite(time) || time <= 0) {
throw new Error('时间格式不正确');
}
return time;
}
function buildBalanceChange(log = {}) {
const type = normalizeType(log.type);
const amount = normalizeAmount(log.amount);
return type === 'income' ? amount : Number((-amount).toFixed(2));
}
function getMerchantLabel(accNo) {
return MERCHANT_MAP[accNo] || '';
}
function buildBalanceInfoMap(source = {}) {
const rawSource = source && typeof source === 'object' ? source : {};
const balanceInfoMap = {};
MERCHANT_OPTIONS.forEach(item => {
const current = rawSource[item.accNo] || {};
balanceInfoMap[item.accNo] = {
accNo: item.accNo,
merchantName: current.merchantName || current.label || item.label,
balance: normalizeAmount(current.balance || 0),
updateTime: current.updateTime || ''
};
});
return balanceInfoMap;
}
function getBalanceInfoList(source = {}) {
const balanceInfoMap = buildBalanceInfoMap(source);
return MERCHANT_OPTIONS.map(item => balanceInfoMap[item.accNo]);
}
function sumBalanceInfoMap(source = {}) {
const balanceInfoMap = buildBalanceInfoMap(source);
return Number(
Object.keys(balanceInfoMap).reduce((sum, accNo) => {
return sum + Number(balanceInfoMap[accNo].balance || 0);
}, 0).toFixed(2)
);
}
function getRemoteResponseObjects(res = {}) {
return {
root: res && typeof res === 'object' ? res : {},
data: res && res.data && typeof res.data === 'object' ? res.data : {},
info: res && res.info && typeof res.info === 'object' ? res.info : {},
content: res && res.content && typeof res.content === 'object' ? res.content : {}
};
}
function pickFirstDefined(values = []) {
return values.find(value => value !== undefined && value !== null && value !== '');
}
function getRemoteMerchantBalance(res = {}) {
const { root, data, info, content } = getRemoteResponseObjects(res);
const canPayAmt = pickFirstDefined([
root.canPayAmt,
data.canPayAmt,
info.canPayAmt,
content.canPayAmt
]);
if (canPayAmt !== undefined) {
return normalizeFenToYuan(canPayAmt);
}
const balanceValue = pickFirstDefined([
data.balance,
info.balance,
content.balance,
data.availableBalance,
info.availableBalance,
content.availableBalance,
data.amount,
info.amount,
content.amount
]);
if (balanceValue !== undefined) {
return normalizeAmount(balanceValue);
}
return null;
}
async function requestMerchantBalance({ vk, accNo }) {
return await vk.request({
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/getInfo',
method: 'POST',
dataType: 'json',
header: {
'content-type': 'application/json; charset=utf-8'
},
data: {
accNo
},
timeout: 60000
});
}
async function requestActionLog({ vk, accNo, reqDate, reqJournalNo }) {
return await vk.request({
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/getActionLog',
method: 'POST',
dataType: 'json',
header: {
'content-type': 'application/json; charset=utf-8'
},
data: {
accNo,
reqDate,
reqJournalNo
},
timeout: 60000
});
}
function pickOrderSet(res = {}) {
const candidates = [
res && res.orderSet,
res && res.data && res.data.orderSet,
res && res.info && res.info.orderSet,
res && res.content && res.content.orderSet,
res && res.data && Array.isArray(res.data) && res.data[0] && res.data[0].orderSet,
res && res.list && Array.isArray(res.list) && res.list[0] && res.list[0].orderSet,
res && res.rows && Array.isArray(res.rows) && res.rows[0] && res.rows[0].orderSet,
res && res.data && res.data.list && Array.isArray(res.data.list) && res.data.list[0] && res.data.list[0].orderSet,
res && res.data && res.data.rows && Array.isArray(res.data.rows) && res.data.rows[0] && res.data.rows[0].orderSet
];
for (let i = 0; i < candidates.length; i++) {
if (typeof candidates[i] === 'string' && candidates[i]) {
return candidates[i];
}
}
return '';
}
function parseOrderSet(res = {}) {
const orderSet = pickOrderSet(res);
if (!orderSet) {
return [];
}
try {
const orderList = JSON.parse(orderSet);
return Array.isArray(orderList) ? orderList : [];
} catch (err) {
console.error('parseOrderSet error', err, orderSet);
return [];
}
}
function getActionStatus(res = {}) {
const orderList = parseOrderSet(res);
if (!orderList.length) {
return null;
}
const firstOrder = orderList[0] || {};
const status = Number(firstOrder.status);
return Number.isFinite(status) ? status : null;
}
function getActionStatusTextByStatus(status) {
const statusMap = {
1: '处理中',
2: '成功',
3: '处理失败',
5: '退票',
6: '退票重提'
};
return statusMap[Number(status)] || '';
}
async function syncMerchantBalance({
vk,
accNo,
merchantBalance,
updateTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
}) {
const balanceRecord = await ensureBalanceRecord({ vk });
const balanceInfoMap = buildBalanceInfoMap(balanceRecord.balanceInfo || {});
const currentMerchantInfo = balanceInfoMap[accNo] || {
accNo,
merchantName: getMerchantLabel(accNo),
balance: 0,
updateTime: ''
};
const currentMerchantBalance = normalizeAmount(currentMerchantInfo.balance || 0);
const nextMerchantBalance = normalizeAmount(merchantBalance);
const nextBalanceInfoMap = {
...balanceInfoMap,
[accNo]: {
accNo,
merchantName: currentMerchantInfo.merchantName || getMerchantLabel(accNo),
balance: nextMerchantBalance,
updateTime
}
};
const nextTotalBalance = Number(
(Number(balanceRecord.balance || 0) - currentMerchantBalance + nextMerchantBalance).toFixed(2)
);
await vk.baseDao.updateById({
dbName: 'jjx-balance',
id: balanceRecord._id,
dataJson: {
balance: nextTotalBalance,
balanceInfo: nextBalanceInfoMap,
updateTime
}
});
return {
balance: nextTotalBalance,
merchantBalance: nextMerchantBalance,
updateTime,
balanceInfoMap: nextBalanceInfoMap
};
}
async function ensureBalanceRecord({ transaction, vk }) {
let balanceInfo = await vk.baseDao.findByWhereJson({
db: transaction,
dbName: 'jjx-balance',
whereJson: {
_id: BALANCE_DOC_ID
}
});
if (!balanceInfo) {
throw new Error(`jjx-balance余额记录不存在: ${BALANCE_DOC_ID}`);
}
return balanceInfo;
}
async function recalculateBalance({ transaction, vk, logId }) {
const res = await vk.baseDao.select({
db: transaction,
dbName: 'jjx-balance-log',
whereJson: {},
sortArr: [{ name: '_add_time', type: 'desc' }],
pageIndex: 1,
pageSize: 5000
});
const balance = Number(res.rows.reduce((sum, item) => sum + buildBalanceChange(item), 0).toFixed(2));
const balanceInfo = await ensureBalanceRecord({ transaction, vk });
await vk.baseDao.updateById({
db: transaction,
dbName: 'jjx-balance',
id: balanceInfo._id,
dataJson: {
balance,
lastLogId: logId || balanceInfo.lastLogId || ''
}
});
return balance;
}
async function checkBalanceAvailable({ transaction, vk, changeAmount, excludeLogId = '' }) {
const balanceInfo = await ensureBalanceRecord({ transaction, vk });
let currentBalance = Number(balanceInfo.balance || 0);
if (excludeLogId) {
const oldLog = await vk.baseDao.findByWhereJson({
db: transaction,
dbName: 'jjx-balance-log',
whereJson: {
_id: excludeLogId
}
});
if (!oldLog) {
throw new Error('原始流水不存在');
}
currentBalance = Number((currentBalance - buildBalanceChange(oldLog)).toFixed(2));
}
const nextBalance = Number((currentBalance + changeAmount).toFixed(2));
if (nextBalance < 0) {
throw new Error('余额不足');
}
return {
currentBalance,
nextBalance
};
}
async function updateBalanceWithDelta({ transaction, vk, delta, lastLogId = '' }) {
const balanceInfo = await ensureBalanceRecord({ transaction, vk });
const nextBalance = Number((Number(balanceInfo.balance || 0) + Number(delta || 0)).toFixed(2));
await vk.baseDao.updateById({
db: transaction,
dbName: 'jjx-balance',
id: balanceInfo._id,
dataJson: {
balance: nextBalance,
lastLogId: lastLogId || balanceInfo.lastLogId || ''
}
});
return nextBalance;
}
async function rollbackTransaction({ transaction, err }) {
try {
await transaction.rollback();
} catch (rollbackErr) {
console.error(rollbackErr);
}
return {
code: -1,
msg: err.message || '操作失败'
};
}
module.exports = {
BALANCE_DOC_ID,
MERCHANT_OPTIONS,
MERCHANT_MAP,
normalizeAmount,
normalizeFenToYuan,
normalizeType,
normalizeTime,
buildBalanceChange,
getMerchantLabel,
buildBalanceInfoMap,
getBalanceInfoList,
sumBalanceInfoMap,
getRemoteResponseObjects,
pickFirstDefined,
getRemoteMerchantBalance,
requestMerchantBalance,
requestActionLog,
pickOrderSet,
parseOrderSet,
getActionStatus,
getActionStatusTextByStatus,
syncMerchantBalance,
ensureBalanceRecord,
recalculateBalance,
checkBalanceAvailable,
updateBalanceWithDelta,
rollbackTransaction
};

Some files were not shown because too many files have changed in this diff Show More