feat: 企业版合作模式(后端、管理端、小程序)

- API:合作模式配置、用户选择、企业版入口与迁移 SQL

- 管理端:合作方式管理、企业/用户侧设置与 CSV 导出等

- 小程序:合作模式弹窗与结果/简历等页对接;开发脚本小调整

Made-with: Cursor
This commit is contained in:
Ghost
2026-04-23 16:08:13 +08:00
parent d7137f9349
commit 830e3611d7
40 changed files with 2518 additions and 33 deletions

View File

@@ -0,0 +1,77 @@
const { request } = require('../../utils/request.js')
Component({
properties: {
visible: {
type: Boolean,
value: false
},
modes: {
type: Array,
value: []
}
},
data: {
selected: '',
submitting: false
},
observers: {
visible(v) {
if (v) {
const modes = this.properties.modes || []
const first = modes.length ? modes[0].code : ''
this.setData({ selected: first || '', submitting: false })
}
},
modes(modes) {
if (this.properties.visible && modes && modes.length) {
const cur = this.data.selected
const ok = modes.some((m) => m && m.code === cur)
if (!ok) this.setData({ selected: modes[0].code })
}
}
},
methods: {
noop() {},
onMask() {},
onRadioChange(e) {
const v = e.detail && e.detail.value ? String(e.detail.value) : ''
if (v) this.setData({ selected: v })
},
onConfirm() {
const code = (this.data.selected || '').trim()
if (!code) {
wx.showToast({ title: '请选择一项', icon: 'none' })
return
}
if (this.data.submitting) return
this.setData({ submitting: true })
request({
url: '/api/user/cooperation-preference',
method: 'POST',
data: { modeCode: code },
success: (res) => {
const body = res.data || {}
if (res.statusCode === 200 && body.code === 200) {
wx.showToast({ title: body.message || '已提交', icon: 'success' })
this.triggerEvent('success', body.data || {})
} else {
wx.showToast({ title: body.message || '提交失败', icon: 'none' })
}
},
fail: () => {
wx.showToast({ title: '网络错误', icon: 'none' })
},
complete: () => {
this.setData({ submitting: false })
}
})
}
}
})

View File

@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1,20 @@
<view class="cmd-mask" wx:if="{{visible}}" catchtouchmove="noop" catchtap="onMask">
<view class="cmd-panel" catchtap="noop">
<text class="cmd-title">请选择合作模式</text>
<text class="cmd-desc">三项测评已完成,请选择与您更契合的合作方式(提交后可在企业侧活动中使用)。</text>
<radio-group class="cmd-list" bindchange="onRadioChange">
<label class="cmd-item" wx:for="{{modes}}" wx:key="code">
<radio value="{{item.code}}" checked="{{selected === item.code}}" color="#ff6b8a" />
<view class="cmd-item-main">
<text class="cmd-item-title">{{item.title}}</text>
<text class="cmd-item-desc">{{item.description}}</text>
</view>
</label>
</radio-group>
<view class="cmd-actions">
<button class="cmd-btn cmd-btn--primary" hover-class="none" loading="{{submitting}}" bindtap="onConfirm">确认提交</button>
</view>
</view>
</view>

View File

@@ -0,0 +1,104 @@
.cmd-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 12500;
background: rgba(15, 23, 42, 0.48);
display: flex;
align-items: center;
justify-content: center;
padding: 48rpx;
box-sizing: border-box;
}
.cmd-panel {
width: 100%;
max-width: 620rpx;
background: #fff;
border-radius: 28rpx;
padding: 40rpx 36rpx 36rpx;
box-shadow: 0 24rpx 80rpx rgba(15, 23, 42, 0.12);
}
.cmd-title {
display: block;
font-size: 34rpx;
font-weight: 700;
color: #111827;
margin-bottom: 16rpx;
}
.cmd-desc {
display: block;
font-size: 24rpx;
line-height: 1.55;
color: #6b7280;
margin-bottom: 28rpx;
}
.cmd-list {
display: block;
}
.cmd-item {
display: flex;
align-items: flex-start;
gap: 16rpx;
padding: 20rpx 0;
border-bottom: 2rpx solid #f3f4f6;
}
.cmd-item:last-child {
border-bottom: none;
}
.cmd-item radio {
margin-top: 6rpx;
}
.cmd-item-main {
flex: 1;
min-width: 0;
}
.cmd-item-title {
display: block;
font-size: 30rpx;
font-weight: 600;
color: #111827;
margin-bottom: 8rpx;
}
.cmd-item-desc {
display: block;
font-size: 24rpx;
line-height: 1.45;
color: #6b7280;
}
.cmd-actions {
margin-top: 28rpx;
}
.cmd-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
font-size: 28rpx;
font-weight: 600;
border-radius: 16rpx;
padding: 0;
margin: 0;
border: none;
}
.cmd-btn::after {
border: none;
}
.cmd-btn--primary {
background: linear-gradient(135deg, #ff6b8a 0%, #ff8e53 100%);
color: #fff;
}