Merge remote-tracking branch 'origin/master'

master
lion 1 week ago
commit 7ebc5d5797

@ -55,13 +55,14 @@ export function destroy(params) {
})
}
export function retry(params) {
export function retry(params, config = {}) {
return request({
method: "get",
url: "/api/admin/appointments/retry-appointment",
params
params,
headers: config.headers,
isLoading: config.isLoading
})
}

@ -0,0 +1,21 @@
import request from '@/utils/request'
export function candidates(params, isLoading = false) {
return request({ method: 'get', url: '/api/admin/qcc-enterprise-accounts/candidates', params, isLoading })
}
export function index(params, isLoading = false) {
return request({ method: 'get', url: '/api/admin/qcc-enterprise-accounts/index', params, isLoading })
}
export function select(data) {
return request({ method: 'post', url: '/api/admin/qcc-enterprise-accounts/select', data, isLoading: true })
}
export function cancel(data) {
return request({ method: 'post', url: '/api/admin/qcc-enterprise-accounts/cancel', data, isLoading: true })
}
export function unknownConfirm(data) {
return request({ method: 'post', url: '/api/admin/qcc-enterprise-accounts/unknown-confirm', data, isLoading: true })
}

@ -37,8 +37,8 @@ export function getAuthMenu(token) {
export function getMsg(param) {
return request({
url: '/api/admin/auth/send-sms',
method: 'get',
params:param,
method: 'post',
data: param,
isLoading: false
})
}
@ -46,8 +46,8 @@ export function getMsg(param) {
export function loginMsg(param) {
return request({
url: '/api/admin/auth/sms-login',
method: 'get',
params:param,
method: 'post',
data: param,
isLoading: false
})
}

@ -76,14 +76,16 @@ const actions = {
loginMsg({
commit
}, userInfo) {
const {
mobile,
code
const {
mobile,
code,
challenge_id
} = userInfo
return new Promise((resolve, reject) => {
loginMsg({
mobile: mobile,
code: code
mobile: mobile,
code: code,
challenge_id: challenge_id
}).then(response => {
console.log(response)
const {

@ -80,7 +80,7 @@
<div style="text-align: left;width:800px;margin: 0 auto;display:flex;">
<div> 第三方记录</div>
<div style="margin-left:30px">
<el-button type="primary" size="small" @click="sendBook(id)">重新预约</el-button>
<el-button type="primary" size="small" :loading="retrying" :disabled="retrying" @click="sendBook(id)">重新预约</el-button>
</div>
</div>
@ -174,9 +174,10 @@
data() {
return {
isShow: false,
type: 'show',
id: '',
submitObj: {},
type: 'show',
id: '',
retrying: false,
submitObj: {},
thirdArr: [],
baseUrl: `${process.env.VUE_APP_BASE_API}`,
form: {
@ -220,16 +221,31 @@
this.$emit('refresh')
})
},
sendBook(id) {
retry({
id: id
}).then(res => {
this.$message({
type: 'success',
message: '重新发送预约成功'
})
this.getDetail()
})
async sendBook(id) {
const traceId = `retry-${id}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
this.retrying = true
try {
await retry({
id: id
}, {
headers: {
'X-Retry-Trace-Id': traceId
},
isLoading: true
})
this.$message({
type: 'success',
message: `已提交重新预约(追踪号:${traceId})`
})
await this.getDetail()
} catch (error) {
const message = error.response && error.response.data && error.response.data.errmsg
? error.response.data.errmsg
: (error.message || '请求未收到响应')
this.$message.error(`重新预约失败:${message}(追踪号:${traceId})`)
} finally {
this.retrying = false
}
},
formatHH(val) {
if (val) {
@ -253,7 +269,8 @@
if (newVal) {
this.getDetail()
} else {
this.id = ''
this.id = ''
this.retrying = false
this.submitObj = {}
this.$refs['dialog'].reset()
}

@ -96,9 +96,12 @@
hasSend: false,
count: 60,
sendTimer: null,
loginForm: {
username: '',
password: ''
loginForm: {
username: '',
password: '',
mobile: '',
code: '',
challenge_id: ''
},
loginRules: {
username: [{
@ -168,7 +171,8 @@
getMsg({
mobile: this.loginForm.mobile
}).then(res => {
this.base.showMessage("发送成功",'success')
this.base.showMessage("发送成功",'success')
this.loginForm.challenge_id = res.challenge_id
// this.$Message.success('发送成功')
// 短信发送后 60s
this.hasSend = true
@ -194,6 +198,10 @@
this.base.showMessage("请输入验证码",'error')
return
}
if (this.base.isNull(this.loginForm.challenge_id)) {
this.base.showMessage("请先获取验证码",'error')
return
}
this.loading = true
let that = this
this.$store.dispatch('user/loginMsg', this.loginForm).then(() => {

@ -0,0 +1,45 @@
<template>
<div v-loading="loading">
<el-table :data="list" border stripe :empty-text="emptyText">
<el-table-column label="企业名称" min-width="220"><template slot-scope="scope">{{ scope.row.company && scope.row.company.company_name }}</template></el-table-column>
<el-table-column label="统一社会信用代码" width="210"><template slot-scope="scope">{{ scope.row.company && scope.row.company.credit_code }}</template></el-table-column>
<el-table-column label="状态" width="130"><template slot-scope="scope"><el-tag :type="statusType(scope.row.status)" size="mini">{{ statusLabel(scope.row.status) }}</el-tag></template></el-table-column>
<el-table-column prop="first_success_at" label="首次成功时间" width="180" />
<el-table-column prop="first_success_source" label="首次成功来源" width="180" />
<el-table-column prop="first_success_ref" label="请求引用" min-width="180" />
<el-table-column v-if="status === 'unknown'" prop="unknown_note" label="待确认原因" min-width="220" />
<el-table-column v-if="status === 'unknown'" label="操作" width="130" fixed="right"><template slot-scope="scope"><el-button type="primary" size="mini" @click="$emit('confirm', scope.row)">人工确认</el-button></template></el-table-column>
</el-table>
<el-pagination class="pagination" background layout="total, prev, pager, next" :current-page="page" :page-size="20" :total="total" @current-change="changePage" />
</div>
</template>
<script>
import { index } from '@/api/qccEnterpriseAccount/index'
const statusMap = { selected: ['warning', '候选'], occupied: ['success', '已占额'], unknown: ['danger', '待人工确认'] }
export default {
name: 'QccAccountList',
props: { status: { type: String, required: true }, emptyText: { type: String, required: true }},
data() { return { list: [], total: 0, page: 1, loading: false } },
created() { this.load() },
methods: {
statusType(status) { return (statusMap[status] || ['info'])[0] },
statusLabel(status) { return (statusMap[status] || ['', ''])[1] },
async load() {
this.loading = true
try {
const res = await index({ status: this.status, page: this.page, page_size: 20 })
this.list = res.data || []
this.total = res.total || 0
} finally { this.loading = false }
},
changePage(page) { this.page = page; this.load() }
}
}
</script>
<style scoped>
.pagination { margin-top: 16px; text-align: right; }
</style>

@ -0,0 +1,69 @@
<template>
<div v-loading="loading" class="qcc-enterprise-account">
<lx-header icon="md-business" :text="$route.meta.title || '企查查企业户标注'" style="margin: 15px 0 10px; border: 0">
<div slot="content"><el-alert title="纳入候选池不会调用企查查。首次调用明确成功后即标记为已占额且不可撤销;状态未知时需先人工确认。" type="warning" :closable="false" show-icon /></div>
</lx-header>
<el-tabs v-model="activeTab">
<el-tab-pane label="候选企业" name="candidates">
<div class="toolbar">
<el-input v-model.trim="candidateQuery.keyword" clearable placeholder="企业名称或统一社会信用代码" style="width: 280px" @keyup.enter.native="loadCandidates" />
<el-select v-model="candidateQuery.status" clearable placeholder="企业户状态" style="width: 150px"><el-option label="未纳入" value="none" /><el-option label="候选" value="selected" /><el-option label="已占额" value="occupied" /><el-option label="待人工确认" value="unknown" /></el-select>
<el-button type="primary" size="small" @click="resetCandidatePage">查询</el-button>
<el-button type="primary" size="small" :disabled="selectedCompanies.length === 0" @click="selectCompanies">纳入候选池</el-button>
</div>
<el-table :data="candidateList" border stripe @selection-change="selectedCompanies = $event">
<el-table-column type="selection" width="50" :selectable="isSelectable" />
<el-table-column prop="company_name" label="企业名称" min-width="220" />
<el-table-column prop="credit_code" label="统一社会信用代码" width="210"><template slot-scope="scope"><span :class="{ 'missing-credit-code': !scope.row.credit_code }">{{ scope.row.credit_code || '缺失,不能纳入' }}</span></template></el-table-column>
<el-table-column label="企业户状态" width="130"><template slot-scope="scope"><el-tag :type="statusType(accountStatus(scope.row))" size="mini">{{ statusLabel(accountStatus(scope.row)) }}</el-tag></template></el-table-column>
<el-table-column prop="updated_at" label="企业信息更新时间" width="180" />
<el-table-column label="操作" width="120" fixed="right"><template slot-scope="scope"><el-button v-if="accountStatus(scope.row) === 'selected'" type="text" @click="cancelCandidate(scope.row.qcc_account.id)">取消候选</el-button><el-button v-else-if="accountStatus(scope.row) === 'unknown'" type="text" @click="openUnknownConfirm(scope.row.qcc_account)">人工确认</el-button></template></el-table-column>
</el-table>
<el-pagination class="pagination" background layout="total, prev, pager, next" :current-page="candidateQuery.page" :page-size="candidateQuery.page_size" :total="candidateTotal" @current-change="changeCandidatePage" />
</el-tab-pane>
<el-tab-pane label="已占额企业" name="occupied"><account-list v-if="activeTab === 'occupied'" status="occupied" empty-text="暂无已占额企业" /></el-tab-pane>
<el-tab-pane label="待人工确认" name="unknown"><account-list v-if="activeTab === 'unknown'" ref="unknownList" status="unknown" empty-text="暂无待人工确认企业" @confirm="openUnknownConfirm" /></el-tab-pane>
</el-tabs>
<el-dialog title="确认未知状态" :visible.sync="confirmDialogVisible" width="560px" :close-on-click-modal="false">
<el-alert title="请先通过企查查其他操作界面核验。确认“已占额”后不可撤销。" type="warning" :closable="false" show-icon />
<el-form label-width="100px" style="margin-top: 18px">
<el-form-item label="确认结论" required><el-radio-group v-model="confirmForm.decision"><el-radio label="retry">确认未成功</el-radio><el-radio label="occupied">确认已占额</el-radio></el-radio-group></el-form-item>
<el-form-item label="核验依据" required><el-input v-model.trim="confirmForm.evidence" type="textarea" :rows="4" maxlength="2000" show-word-limit placeholder="填写企查查操作记录号、截图编号或核验说明" /></el-form-item>
</el-form>
<div slot="footer"><el-button @click="confirmDialogVisible = false">取消</el-button><el-button type="primary" :loading="confirming" @click="confirmUnknown">确认</el-button></div>
</el-dialog>
</div>
</template>
<script>
import { candidates, select, cancel, unknownConfirm } from '@/api/qccEnterpriseAccount/index'
import AccountList from './components/AccountList'
const statusMap = { none: ['info', '未纳入'], selected: ['warning', '候选'], occupied: ['success', '已占额'], unknown: ['danger', '待人工确认'] }
export default {
name: 'QccEnterpriseAccount', components: { AccountList },
data() { return { activeTab: 'candidates', loading: false, candidateList: [], candidateTotal: 0, selectedCompanies: [], candidateQuery: { keyword: '', status: '', page: 1, page_size: 20 }, confirmDialogVisible: false, confirming: false, confirmForm: { id: '', decision: 'retry', evidence: '' }} },
created() { this.loadCandidates() },
methods: {
accountStatus(company) { return company.qcc_account ? company.qcc_account.status : 'none' },
statusType(status) { return (statusMap[status] || statusMap.none)[0] },
statusLabel(status) { return (statusMap[status] || statusMap.none)[1] },
isSelectable(row) { return Boolean(row.credit_code) && this.accountStatus(row) === 'none' },
async loadCandidates() { this.loading = true; this.selectedCompanies = []; try { const res = await candidates(this.candidateQuery); this.candidateList = res.data || []; this.candidateTotal = res.total || 0 } finally { this.loading = false } },
resetCandidatePage() { this.candidateQuery.page = 1; this.loadCandidates() },
changeCandidatePage(page) { this.candidateQuery.page = page; this.loadCandidates() },
async selectCompanies() { await select({ company_ids: this.selectedCompanies.map(item => item.id) }); this.$message.success('已纳入候选池,尚未发生外部调用'); this.selectedCompanies = []; this.loadCandidates() },
async cancelCandidate(id) { await this.$confirm('仅候选状态可取消,确认继续吗?', '取消候选', { type: 'warning' }); await cancel({ id }); this.$message.success('已取消候选关系'); this.loadCandidates() },
openUnknownConfirm(account) { this.confirmForm = { id: account.id, decision: 'retry', evidence: '' }; this.confirmDialogVisible = true },
async confirmUnknown() { if (!this.confirmForm.evidence) return this.$message.warning('请填写核验依据'); if (this.confirmForm.decision === 'occupied') await this.$confirm('确认已占额后不可撤销,确认继续吗?', '不可撤销确认', { type: 'warning' }); this.confirming = true; try { await unknownConfirm(this.confirmForm); this.$message.success('状态已确认'); this.confirmDialogVisible = false; if (this.$refs.unknownList) this.$refs.unknownList.load(); this.loadCandidates() } finally { this.confirming = false } }
}
}
</script>
<style lang="scss" scoped>
.toolbar { display: flex; gap: 10px; margin-bottom: 15px; }
.pagination { margin-top: 16px; text-align: right; }
.missing-credit-code { color: #f56c6c; }
</style>

@ -32,7 +32,7 @@ module.exports = {
// outputDir: '/Users/mac/Documents/朗业/2024/s-苏州科技商学院/wx.sstbc.com/public/admin',
// 测试
// outputDir: '/Users/mac/Documents/朗业/2025/s-苏州科技商学院/wx.sstbc.com/public/admin',
outputDir: '/Users/mac/Documents/朗业/2026/s-苏州科技商学院/code/wx.sstbc.com/public/admin',
outputDir: '../backend/public/admin',
assetsDir: 'static',
css: {
loaderOptions: { // 向 CSS 相关的 loader 传递选项

Loading…
Cancel
Save