| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- /** Run: node java/scripts/fix-industry-corpus-matrix-vue.js */
- const fs = require('fs')
- const path = require('path')
- const root = path.resolve(__dirname, '../..')
- const T = String.raw
- const vue = T`<template>
- <div class="app-container industry-corpus-page">
- <el-form :inline="true" class="list-search-form mb8">
- <LobsterCompanyUserFilter
- :company-id.sync="queryParams.subCompanyId"
- :company-user-id.sync="queryParams.companyUserId"
- @change="handleCompanyChange"
- />
- <el-form-item label="${'\u573a\u666f'}">
- <el-select v-model="queryParams.scenario" placeholder="${'\u5168\u90e8\u573a\u666f'}" clearable size="small" @change="handleQuery">
- <el-option v-for="s in scenarios" :key="s.code" :label="s.name" :value="s.code" />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">${'\u641c\u7d22'}</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">${'\u91cd\u7f6e'}</el-button>
- <el-button type="success" plain icon="el-icon-magic-stick" size="mini" @click="handleSeed(false)">${'\u521d\u59cb\u5316\u5f53\u524d\u884c\u4e1a'}</el-button>
- <el-button type="info" plain icon="el-icon-cpu" size="mini" @click="openEnrichDialog">AI+${'\u8054\u7f51\u8865\u9f50'}</el-button>
- <el-button type="warning" plain icon="el-icon-download" size="mini" @click="openImportDialog">${'\u4ece\u9500\u51a0\u8bed\u6599\u5bfc\u5165'}</el-button>
- <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">${'\u65b0\u589e\u6761\u76ee'}</el-button>
- </el-form-item>
- </el-form>
- <el-tabs v-model="activeIndustry" type="card" @tab-click="handleIndustryTab">
- <el-tab-pane v-for="ind in industries" :key="ind.code" :label="ind.labelZh || ind.label" :name="ind.code" />
- </el-tabs>
- <el-alert v-if="overview.total === 0" type="info" show-icon :closable="false" class="mb8">
- ${'\u5f53\u524d\u884c\u4e1a\u5c1a\u672a\u521d\u59cb\u5316\u8bed\u6599\u77e9\u9635\uff0cUDD \u6df1\u5ea6\u5bf9\u8bdd\u5c06\u65e0\u6cd5\u6ce8\u5165\u884c\u4e1a\u98ce\u683c\u53c2\u8003\u3002\u53ef\u5148\u300c\u521d\u59cb\u5316\u300d\u3001\u300cAI+\u8054\u7f51\u8865\u9f50\u300d\u6216\u4ece\u9500\u51a0\u8bed\u6599\u5bfc\u5165\u3002'}
- </el-alert>
- <el-alert v-else type="success" show-icon :closable="false" class="mb8">
- ${'\u5171'} {{ overview.total }} ${'\u6761\u8bed\u6599\uff0c\u8986\u76d6'} {{ (overview.scenarioCounts || []).length }} ${'\u4e2a\u573a\u666f\uff0c\u4f9b UDD \u6df1\u5ea6\u5bf9\u8bdd\u5f15\u7528\u3002'}
- </el-alert>
- <el-table class="lobster-list-table" border v-loading="loading" :data="list">
- <el-table-column label="${'\u573a\u666f'}" prop="scenario" width="100">
- <template slot-scope="scope">{{ scenarioLabel(scope.row.scenario) }}</template>
- </el-table-column>
- <el-table-column label="${'\u5ba2\u6237\u95ee\u9898'}" prop="customerQuestion" min-width="220" show-overflow-tooltip />
- <el-table-column label="${'\u9500\u51a0\u56de\u590d'}" prop="salesAnswer" min-width="260" show-overflow-tooltip />
- <el-table-column label="${'\u6765\u6e90'}" prop="sourceType" width="110" />
- <el-table-column label="${'\u542f\u7528'}" width="70" align="center">
- <template slot-scope="scope">
- <el-tag :type="scope.row.enabled === 1 ? 'success' : 'info'" size="mini">
- {{ scope.row.enabled === 1 ? '${'\u662f'}' : '${'\u5426'}' }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="${'\u64cd\u4f5c'}" width="140" fixed="right" align="center">
- <template slot-scope="scope">
- <el-button type="text" size="mini" @click="handleEdit(scope.row)">${'\u7f16\u8f91'}</el-button>
- <el-button type="text" size="mini" style="color:#F56C6C" @click="handleDelete(scope.row)">${'\u5220\u9664'}</el-button>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="total>0" :total="total" :page.sync="queryParams.page" :limit.sync="queryParams.size" @pagination="getList" />
- <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="720px" append-to-body @closed="resetForm">
- <el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
- <el-form-item label="${'\u884c\u4e1a'}"><el-input :value="industryLabel(activeIndustry)" disabled /></el-form-item>
- <el-form-item label="${'\u573a\u666f'}" prop="scenario">
- <el-select v-model="form.scenario" placeholder="${'\u8bf7\u9009\u62e9\u573a\u666f'}" style="width:100%">
- <el-option v-for="s in scenarios" :key="s.code" :label="s.name" :value="s.code" />
- </el-select>
- </el-form-item>
- <el-form-item label="${'\u5ba2\u6237\u95ee\u9898'}" prop="customerQuestion">
- <el-input v-model="form.customerQuestion" type="textarea" :rows="3" placeholder="${'\u6a21\u62df\u5ba2\u6237\u4f1a\u95ee\u4ec0\u4e48'}" />
- </el-form-item>
- <el-form-item label="${'\u9500\u51a0\u56de\u590d'}" prop="salesAnswer">
- <el-input v-model="form.salesAnswer" type="textarea" :rows="4" placeholder="UDD${'\u98ce\u683c\uff1a\u7b54+\u70b9\u7834\u4fe1\u53f7+\u5171\u60c5+\u5355\u7ef4\u8ffd\u95ee'}" />
- </el-form-item>
- <el-form-item label="${'\u542f\u7528'}"><el-switch v-model="form.enabled" :active-value="1" :inactive-value="0" /></el-form-item>
- </el-form>
- <div slot="footer">
- <el-button @click="dialogVisible=false">${'\u53d6\u6d88'}</el-button>
- <el-button type="primary" :loading="submitLoading" @click="submitForm">${'\u786e\u5b9a'}</el-button>
- </div>
- </el-dialog>
- <el-dialog title="${'\u4ece\u9500\u51a0\u8bed\u6599\u5bfc\u5165'}" :visible.sync="importVisible" width="560px" append-to-body>
- <el-form label-width="100px" size="small">
- <el-form-item label="${'\u76ee\u6807\u884c\u4e1a'}"><el-input :value="industryLabel(activeIndustry)" disabled /></el-form-item>
- <el-form-item label="${'\u9500\u51a0\u4efb\u52a1'}">
- <el-select v-model="importForm.taskId" placeholder="${'\u9009\u62e9\u5df2\u5206\u6790\u7684\u9500\u51a0\u4efb\u52a1'}" filterable style="width:100%">
- <el-option v-for="t in salesTasks" :key="t.id" :label="(t.taskName || t.batchNo || t.id) + '\uff08${'\u5408\u683c'}' + (t.qualifiedCount || 0) + '\uff09'" :value="t.id" />
- </el-select>
- </el-form-item>
- <el-form-item label="${'\u4ec5\u5408\u683c\u6761\u76ee'}"><el-switch v-model="importForm.onlyQualified" /></el-form-item>
- </el-form>
- <div slot="footer">
- <el-button @click="importVisible=false">${'\u53d6\u6d88'}</el-button>
- <el-button type="primary" :loading="importLoading" @click="submitImport">${'\u786e\u8ba4\u5bfc\u5165'}</el-button>
- </div>
- </el-dialog>
- <el-dialog title="AI + ${'\u8054\u7f51\u8865\u9f50\u884c\u4e1a\u8bed\u6599'}" :visible.sync="enrichVisible" width="640px" append-to-body>
- <el-alert type="info" show-icon :closable="false" class="mb12">${'\u5c06\u6309\u573a\u666f\u8054\u7f51\u68c0\u7d22\u884c\u4e1a\u8d44\u6599\uff0c\u5e76\u7ed3\u5408\u79df\u6237\u77e5\u8bc6\u5e93\u4e0e LLM \u751f\u6210 UDD \u8bed\u6599\u77e9\u9635\u6761\u76ee\uff1b\u53ef\u9009\u540c\u6b65\u5199\u5165\u5411\u91cf\u77e5\u8bc6\u5e93\u3002'}</el-alert>
- <el-form label-width="110px" size="small">
- <el-form-item label="${'\u76ee\u6807\u884c\u4e1a'}"><el-input :value="industryLabel(activeIndustry)" disabled /></el-form-item>
- <el-form-item label="${'\u8865\u9f50\u573a\u666f'}">
- <el-select v-model="enrichForm.scenarios" multiple placeholder="${'\u9ed8\u8ba4\u5168\u90e88\u573a\u666f'}" style="width:100%">
- <el-option v-for="s in scenarios" :key="s.code" :label="s.name" :value="s.code" />
- </el-select>
- </el-form-item>
- <el-form-item label="${'\u8054\u7f51\u68c0\u7d22'}">
- <el-switch v-model="enrichForm.useWebSearch" />
- <span class="form-tip">${'\u672a\u914d\u7f6e\u535a\u67e5\u7b49 API \u65f6\u4f7f\u7528 DuckDuckGo \u516c\u5f00\u63a5\u53e3\u515c\u5e95'}</span>
- </el-form-item>
- <el-form-item label="${'\u5f15\u7528\u77e5\u8bc6\u5e93'}"><el-switch v-model="enrichForm.useKnowledgeBase" /></el-form-item>
- <el-form-item label="${'\u8df3\u8fc7\u5df2\u6709\u95ee\u9898'}"><el-switch v-model="enrichForm.skipExisting" /></el-form-item>
- <el-form-item label="${'\u540c\u6b65\u5199\u77e5\u8bc6\u5e93'}"><el-switch v-model="enrichForm.writeToKb" /></el-form-item>
- <el-form-item v-if="enrichForm.writeToKb" label="${'\u77e5\u8bc6\u5e93ID'}">
- <el-input v-model.number="enrichForm.knowledgeBaseId" placeholder="company_knowledge_base.base_id" />
- </el-form-item>
- </el-form>
- <div v-if="enrichPreview.length" class="enrich-preview">
- <div class="preview-title">${'\u672c\u6b21\u751f\u6210\u9884\u89c8\uff08\u6700\u591a20\u6761\uff09'}</div>
- <el-table :data="enrichPreview" border size="mini" max-height="220">
- <el-table-column label="${'\u573a\u666f'}" prop="scenario" width="80" />
- <el-table-column label="${'\u5ba2\u6237\u95ee\u9898'}" prop="customerQuestion" min-width="140" show-overflow-tooltip />
- <el-table-column label="${'\u9500\u51a0\u56de\u590d'}" prop="salesAnswer" min-width="160" show-overflow-tooltip />
- </el-table>
- </div>
- <div slot="footer">
- <el-button @click="enrichVisible=false">${'\u53d6\u6d88'}</el-button>
- <el-button type="primary" :loading="enrichLoading" @click="submitEnrich">${'\u5f00\u59cb\u8865\u9f50'}</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import {
- listIndustryCorpusMatrix, getIndustryCorpusOverview, seedIndustryCorpusMatrix,
- addIndustryCorpusEntry, updateIndustryCorpusEntry, deleteIndustryCorpusEntry,
- listIndustryCorpusIndustries, listIndustryCorpusScenarios, importIndustryCorpusFromSales,
- enrichIndustryCorpusByAiWeb, listSalesCorpusTasks
- } from '@/api/workflow/lobster'
- import LobsterCompanyUserFilter from '../components/LobsterCompanyUserFilter.vue'
- export default {
- name: 'IndustryCorpusMatrix',
- components: { LobsterCompanyUserFilter },
- data() {
- return {
- loading: false, submitLoading: false, importLoading: false, enrichLoading: false,
- list: [], total: 0, industries: [], scenarios: [], salesTasks: [], enrichPreview: [],
- activeIndustry: 'general', overview: { total: 0, scenarioCounts: [] },
- queryParams: { page: 1, size: 20, scenario: null, subCompanyId: null, companyUserId: null },
- dialogVisible: false, importVisible: false, enrichVisible: false,
- dialogTitle: '${'\u65b0\u589e\u8bed\u6599'}',
- form: { id: null, scenario: 'consult', customerQuestion: '', salesAnswer: '', enabled: 1 },
- importForm: { taskId: null, onlyQualified: true },
- enrichForm: { scenarios: [], useWebSearch: true, useKnowledgeBase: true, skipExisting: true, writeToKb: false, knowledgeBaseId: null },
- rules: {
- scenario: [{ required: true, message: '${'\u8bf7\u9009\u62e9\u573a\u666f'}', trigger: 'change' }],
- customerQuestion: [{ required: true, message: '${'\u8bf7\u8f93\u5165\u5ba2\u6237\u95ee\u9898'}', trigger: 'blur' }],
- salesAnswer: [{ required: true, message: '${'\u8bf7\u8f93\u5165\u9500\u51a0\u56de\u590d'}', trigger: 'blur' }]
- }
- }
- },
- created() { this.loadMeta() },
- methods: {
- loadMeta() {
- Promise.all([listIndustryCorpusIndustries(), listIndustryCorpusScenarios()]).then(([indRes, scRes]) => {
- this.industries = indRes.data || []
- this.scenarios = scRes.data || []
- if (this.industries.length && !this.activeIndustry) this.activeIndustry = this.industries[0].code
- this.loadOverview(); this.getList()
- })
- },
- industryLabel(code) { const f = this.industries.find(i => i.code === code); return f ? (f.labelZh || f.label) : code },
- scenarioLabel(code) { const f = this.scenarios.find(s => s.code === code); return f ? f.name : code },
- handleCompanyChange() { this.handleQuery() },
- handleIndustryTab() { this.queryParams.page = 1; this.loadOverview(); this.getList() },
- loadOverview() {
- if (!this.activeIndustry) return
- getIndustryCorpusOverview(this.activeIndustry, this.queryParams.subCompanyId).then(res => {
- this.overview = res.data || { total: 0, scenarioCounts: [] }
- })
- },
- getList() {
- this.loading = true
- listIndustryCorpusMatrix({
- page: this.queryParams.page, size: this.queryParams.size,
- industryType: this.activeIndustry, scenario: this.queryParams.scenario,
- companyId: this.queryParams.subCompanyId
- }).then(res => {
- const d = res.data || {}; this.list = d.list || []; this.total = d.total || 0
- }).finally(() => { this.loading = false })
- },
- handleQuery() { this.queryParams.page = 1; this.loadOverview(); this.getList() },
- resetQuery() { this.queryParams.scenario = null; this.handleQuery() },
- handleSeed(force) {
- const label = this.industryLabel(this.activeIndustry)
- const msg = force
- ? '${'\u786e\u8ba4\u4e3a\u300c'}' + label + '${'\u300d\u8ffd\u52a0\u884c\u4e1a\u6a21\u677f\u8bed\u6599\uff1f'}'
- : '${'\u786e\u8ba4\u4e3a\u300c'}' + label + '${'\u300d\u521d\u59cb\u5316\u884c\u4e1a\u8bed\u6599\u77e9\u9635\uff08\u5df2\u6709\u8bed\u6599\u5219\u8df3\u8fc7\uff09\uff1f'}'
- this.$confirm(msg, '${'\u63d0\u793a'}', { type: 'warning' }).then(() => {
- seedIndustryCorpusMatrix(this.activeIndustry, force, this.queryParams.subCompanyId).then(res => {
- this.$message.success((res.data && res.data.message) || '${'\u64cd\u4f5c\u6210\u529f'}')
- this.loadOverview(); this.getList()
- })
- }).catch(() => {})
- },
- openImportDialog() {
- this.importForm = { taskId: null, onlyQualified: true }
- listSalesCorpusTasks({ page: 1, size: 100 }).then(res => {
- this.salesTasks = (res.data || {}).list || (res.data || {}).rows || []
- this.importVisible = true
- })
- },
- submitImport() {
- if (!this.importForm.taskId) { this.$message.warning('${'\u8bf7\u9009\u62e9\u9500\u51a0\u4efb\u52a1'}'); return }
- this.importLoading = true
- importIndustryCorpusFromSales({
- industryType: this.activeIndustry, taskId: this.importForm.taskId,
- onlyQualified: this.importForm.onlyQualified, companyId: this.queryParams.subCompanyId
- }).then(res => {
- this.$message.success((res.data && res.data.message) || '${'\u5bfc\u5165\u6210\u529f'}')
- this.importVisible = false; this.loadOverview(); this.getList()
- }).finally(() => { this.importLoading = false })
- },
- openEnrichDialog() {
- this.enrichPreview = []
- this.enrichForm = { scenarios: [], useWebSearch: true, useKnowledgeBase: true, skipExisting: true, writeToKb: false, knowledgeBaseId: null }
- this.enrichVisible = true
- },
- submitEnrich() {
- if (this.enrichForm.writeToKb && !this.enrichForm.knowledgeBaseId) { this.$message.warning('${'\u8bf7\u586b\u5199\u77e5\u8bc6\u5e93 ID'}'); return }
- const label = this.industryLabel(this.activeIndustry)
- this.$confirm('${'\u5c06\u4e3a\u300c'}' + label + '${'\u300d\u6267\u884c AI+\u8054\u7f51\u8865\u9f50\uff0c\u53ef\u80fd\u8017\u65f6 1-3 \u5206\u949f\uff0c\u662f\u5426\u7ee7\u7eed\uff1f'}', '${'\u63d0\u793a'}', { type: 'warning' })
- .then(() => {
- this.enrichLoading = true
- return enrichIndustryCorpusByAiWeb({
- industryType: this.activeIndustry,
- scenarios: this.enrichForm.scenarios && this.enrichForm.scenarios.length ? this.enrichForm.scenarios : null,
- useWebSearch: this.enrichForm.useWebSearch, useKnowledgeBase: this.enrichForm.useKnowledgeBase,
- skipExisting: this.enrichForm.skipExisting, writeToKb: this.enrichForm.writeToKb,
- knowledgeBaseId: this.enrichForm.writeToKb ? this.enrichForm.knowledgeBaseId : null,
- companyId: this.queryParams.subCompanyId
- })
- }).then(res => {
- if (!res) return
- const d = res.data || {}
- this.enrichPreview = d.preview || []
- this.$message.success(d.message || '${'\u8865\u9f50\u5b8c\u6210'}')
- this.loadOverview(); this.getList()
- }).finally(() => { this.enrichLoading = false }).catch(() => {})
- },
- handleAdd() {
- this.dialogTitle = '${'\u65b0\u589e\u8bed\u6599'}'
- this.form = { id: null, scenario: 'consult', customerQuestion: '', salesAnswer: '', enabled: 1 }
- this.dialogVisible = true
- },
- handleEdit(row) {
- this.dialogTitle = '${'\u7f16\u8f91\u8bed\u6599'}'
- this.form = { id: row.id, scenario: row.scenario, customerQuestion: row.customerQuestion, salesAnswer: row.salesAnswer, enabled: row.enabled != null ? row.enabled : 1 }
- this.dialogVisible = true
- },
- handleDelete(row) {
- this.$confirm('${'\u786e\u8ba4\u5220\u9664\u8be5\u8bed\u6599\u6761\u76ee\uff1f'}', '${'\u63d0\u793a'}', { type: 'warning' }).then(() => {
- deleteIndustryCorpusEntry(row.id, this.queryParams.subCompanyId).then(() => {
- this.$message.success('${'\u5df2\u5220\u9664'}'); this.loadOverview(); this.getList()
- })
- }).catch(() => {})
- },
- resetForm() { if (this.$refs.formRef) this.$refs.formRef.resetFields() },
- submitForm() {
- this.$refs.formRef.validate(valid => {
- if (!valid) return
- this.submitLoading = true
- const payload = {
- industryType: this.activeIndustry, scenario: this.form.scenario,
- customerQuestion: this.form.customerQuestion, salesAnswer: this.form.salesAnswer,
- enabled: this.form.enabled, companyId: this.queryParams.subCompanyId
- }
- const req = this.form.id ? updateIndustryCorpusEntry(this.form.id, payload) : addIndustryCorpusEntry(payload)
- req.then(() => {
- this.$message.success('${'\u4fdd\u5b58\u6210\u529f'}'); this.dialogVisible = false; this.loadOverview(); this.getList()
- }).finally(() => { this.submitLoading = false })
- })
- }
- }
- }
- </script>
- <style scoped>
- .industry-corpus-page >>> .el-tabs__header { margin-bottom: 12px; }
- .industry-corpus-page .mb12 { margin-bottom: 12px; }
- .industry-corpus-page .form-tip { margin-left: 8px; color: #909399; font-size: 12px; }
- .industry-corpus-page .preview-title { font-weight: 600; margin-bottom: 8px; }
- </style>
- `
- const target = path.join(root, 'saas-mgnui/src/views/lobster/industry-corpus-matrix/index.vue')
- fs.writeFileSync(target, vue, 'utf8')
- const check = fs.readFileSync(target, 'utf8')
- console.log('written', check.includes('\u573a\u666f'), !check.includes('\ufffd'), check.split('\n')[8])
|