|
|
@@ -1,36 +1,614 @@
|
|
|
<template>
|
|
|
- <div class="ontology-workbench pa-6">
|
|
|
- <div class="d-flex align-center mb-4">
|
|
|
- <div><h1 class="text-h4">本体工作台</h1><p class="text--secondary">图定义、校验、版本差异与发布确认</p></div>
|
|
|
+ <div class="ontology-workbench pa-5">
|
|
|
+ <div class="workbench-header d-flex align-center mb-4">
|
|
|
+ <v-btn icon class="mr-2" @click="$router.push('/data-governance/ontology')">
|
|
|
+ <v-icon>mdi-arrow-left</v-icon>
|
|
|
+ </v-btn>
|
|
|
+ <div>
|
|
|
+ <div class="d-flex align-center">
|
|
|
+ <h1 class="text-h5 mb-0">{{ ontology.name || '本体工作台' }}</h1>
|
|
|
+ <v-chip
|
|
|
+ v-if="ontology.status"
|
|
|
+ x-small
|
|
|
+ outlined
|
|
|
+ class="ml-3"
|
|
|
+ :color="ontology.status === 'published' ? 'success' : 'warning'"
|
|
|
+ >
|
|
|
+ {{ ontology.status }}
|
|
|
+ </v-chip>
|
|
|
+ </div>
|
|
|
+ <div class="text-caption text--secondary mt-1">
|
|
|
+ {{ ontology.code || $route.params.uid }} · 草稿修订 {{ revision }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
<v-spacer />
|
|
|
- <v-btn outlined class="mr-2" @click="validate">校验</v-btn>
|
|
|
- <v-btn color="primary" @click="publishDialog = true">发布确认</v-btn>
|
|
|
+ <v-btn v-if="canEdit" text small class="mr-1" @click="importDialog = true">
|
|
|
+ <v-icon left small>mdi-import</v-icon>导入
|
|
|
+ </v-btn>
|
|
|
+ <v-menu offset-y>
|
|
|
+ <template #activator="{ on, attrs }">
|
|
|
+ <v-btn text small class="mr-1" v-bind="attrs" v-on="on">
|
|
|
+ <v-icon left small>mdi-export</v-icon>导出
|
|
|
+ </v-btn>
|
|
|
+ </template>
|
|
|
+ <v-list dense>
|
|
|
+ <v-list-item @click="exportDocument('json')">
|
|
|
+ <v-list-item-title>导出 JSON</v-list-item-title>
|
|
|
+ </v-list-item>
|
|
|
+ <v-list-item @click="exportDocument('owl')">
|
|
|
+ <v-list-item-title>导出 OWL/RDF</v-list-item-title>
|
|
|
+ </v-list-item>
|
|
|
+ </v-list>
|
|
|
+ </v-menu>
|
|
|
+ <v-btn
|
|
|
+ v-if="canEdit"
|
|
|
+ outlined
|
|
|
+ small
|
|
|
+ color="primary"
|
|
|
+ class="mr-2"
|
|
|
+ @click="generateSuggestions"
|
|
|
+ >
|
|
|
+ <v-icon left small>mdi-lightbulb-on-outline</v-icon>动态建议
|
|
|
+ </v-btn>
|
|
|
+ <v-btn
|
|
|
+ v-if="canEdit"
|
|
|
+ outlined
|
|
|
+ small
|
|
|
+ class="mr-2"
|
|
|
+ :loading="saving"
|
|
|
+ @click="save"
|
|
|
+ >
|
|
|
+ 保存草稿
|
|
|
+ </v-btn>
|
|
|
+ <v-btn
|
|
|
+ v-if="canEdit"
|
|
|
+ outlined
|
|
|
+ small
|
|
|
+ class="mr-2"
|
|
|
+ :loading="validating"
|
|
|
+ @click="validate"
|
|
|
+ >
|
|
|
+ 校验
|
|
|
+ </v-btn>
|
|
|
+ <v-btn
|
|
|
+ v-if="canPublish"
|
|
|
+ color="primary"
|
|
|
+ small
|
|
|
+ :disabled="!versions.length"
|
|
|
+ @click="publishDialog = true"
|
|
|
+ >
|
|
|
+ 发布确认
|
|
|
+ </v-btn>
|
|
|
</div>
|
|
|
+
|
|
|
+ <v-alert v-if="!canEdit" type="info" outlined dense>
|
|
|
+ 当前为只读模式,可查看本体、校验结果和已发布版本。
|
|
|
+ </v-alert>
|
|
|
+
|
|
|
<v-row>
|
|
|
- <v-col cols="8"><v-textarea v-model="graphJson" outlined auto-grow label="本体图 JSON" /></v-col>
|
|
|
- <v-col cols="4">
|
|
|
- <v-card outlined><v-card-title>校验结果</v-card-title><v-card-text>
|
|
|
- <v-alert v-for="issue in issues" :key="issue.code" type="warning" dense>{{ issue.code }} · {{ issue.message }}</v-alert>
|
|
|
- <span v-if="!issues.length">尚无校验问题</span>
|
|
|
- </v-card-text></v-card>
|
|
|
- <v-card outlined class="mt-4"><v-card-title>版本差异</v-card-title><v-card-text><pre>{{ diff }}</pre></v-card-text></v-card>
|
|
|
+ <v-col cols="2">
|
|
|
+ <v-card outlined class="section-nav">
|
|
|
+ <v-list dense nav>
|
|
|
+ <v-list-item
|
|
|
+ v-for="section in sections"
|
|
|
+ :key="section.value"
|
|
|
+ :input-value="selectedSection === section.value"
|
|
|
+ color="primary"
|
|
|
+ @click="selectedSection = section.value"
|
|
|
+ >
|
|
|
+ <v-list-item-icon>
|
|
|
+ <v-icon small>{{ section.icon }}</v-icon>
|
|
|
+ </v-list-item-icon>
|
|
|
+ <v-list-item-content>
|
|
|
+ <v-list-item-title>{{ section.text }}</v-list-item-title>
|
|
|
+ </v-list-item-content>
|
|
|
+ <v-list-item-action>
|
|
|
+ <span class="text-caption">{{ graph[section.value].length }}</span>
|
|
|
+ </v-list-item-action>
|
|
|
+ </v-list-item>
|
|
|
+ </v-list>
|
|
|
+ <v-divider />
|
|
|
+ <v-list dense>
|
|
|
+ <v-list-item @click="openJsonEditor">
|
|
|
+ <v-list-item-icon><v-icon small>mdi-code-json</v-icon></v-list-item-icon>
|
|
|
+ <v-list-item-title>高级 JSON</v-list-item-title>
|
|
|
+ </v-list-item>
|
|
|
+ </v-list>
|
|
|
+ </v-card>
|
|
|
+ </v-col>
|
|
|
+
|
|
|
+ <v-col cols="7">
|
|
|
+ <graph-section-editor
|
|
|
+ :section="selectedSection"
|
|
|
+ :items="graph[selectedSection]"
|
|
|
+ :graph="graph"
|
|
|
+ :domains="domainOptions"
|
|
|
+ :data-elements="dataElementOptions"
|
|
|
+ :read-only="!canEdit"
|
|
|
+ @upsert="upsertItem"
|
|
|
+ @remove="removeItem"
|
|
|
+ />
|
|
|
+ </v-col>
|
|
|
+
|
|
|
+ <v-col cols="3">
|
|
|
+ <v-card outlined class="validation-panel">
|
|
|
+ <v-card-title class="text-subtitle-1">校验结果</v-card-title>
|
|
|
+ <v-divider />
|
|
|
+ <v-card-text>
|
|
|
+ <v-alert v-if="!hasValidated" type="info" text dense>
|
|
|
+ 尚未执行校验。请先保存草稿,再点击“校验”。
|
|
|
+ </v-alert>
|
|
|
+ <v-alert
|
|
|
+ v-else-if="!issues.length"
|
|
|
+ type="success"
|
|
|
+ text
|
|
|
+ dense
|
|
|
+ >
|
|
|
+ 当前草稿校验通过。
|
|
|
+ </v-alert>
|
|
|
+ <v-alert
|
|
|
+ v-for="issue in issues"
|
|
|
+ :key="`${issue.code}-${issue.path}`"
|
|
|
+ type="warning"
|
|
|
+ outlined
|
|
|
+ dense
|
|
|
+ >
|
|
|
+ <strong>{{ issue.code }}</strong>
|
|
|
+ <div>{{ issue.message }}</div>
|
|
|
+ <div v-if="issue.path" class="text-caption mt-1">
|
|
|
+ 位置:{{ issue.path }}
|
|
|
+ </div>
|
|
|
+ </v-alert>
|
|
|
+ </v-card-text>
|
|
|
+ </v-card>
|
|
|
+
|
|
|
+ <v-card outlined class="mt-4">
|
|
|
+ <v-card-title class="text-subtitle-1">本体摘要</v-card-title>
|
|
|
+ <v-divider />
|
|
|
+ <v-list dense>
|
|
|
+ <v-list-item>
|
|
|
+ <v-list-item-content>主责人</v-list-item-content>
|
|
|
+ <v-list-item-action>{{ ontology.owner_uid || '-' }}</v-list-item-action>
|
|
|
+ </v-list-item>
|
|
|
+ <v-list-item>
|
|
|
+ <v-list-item-content>当前版本</v-list-item-content>
|
|
|
+ <v-list-item-action>{{ latestVersionLabel }}</v-list-item-action>
|
|
|
+ </v-list-item>
|
|
|
+ <v-list-item>
|
|
|
+ <v-list-item-content>关联业务域</v-list-item-content>
|
|
|
+ <v-list-item-action>{{ graph.domain_links.length }}</v-list-item-action>
|
|
|
+ </v-list-item>
|
|
|
+ <v-list-item>
|
|
|
+ <v-list-item-content>数据元素映射</v-list-item-content>
|
|
|
+ <v-list-item-action>{{ graph.element_mappings.length }}</v-list-item-action>
|
|
|
+ </v-list-item>
|
|
|
+ </v-list>
|
|
|
+ </v-card>
|
|
|
</v-col>
|
|
|
</v-row>
|
|
|
- <v-btn color="primary" @click="save">保存草稿</v-btn>
|
|
|
- <v-dialog v-model="publishDialog" max-width="480"><v-card><v-card-title>发布确认</v-card-title><v-card-text>发布后该版本不可修改,并将异步投影至语义图。</v-card-text><v-card-actions><v-spacer /><v-btn text @click="publishDialog = false">取消</v-btn><v-btn color="primary" @click="publish">确认发布</v-btn></v-card-actions></v-card></v-dialog>
|
|
|
+
|
|
|
+ <version-workspace
|
|
|
+ class="mt-4"
|
|
|
+ :versions="versions"
|
|
|
+ :diff="diff"
|
|
|
+ :can-rollback="canPublish"
|
|
|
+ :loading="versionLoading"
|
|
|
+ @compare="compareVersions"
|
|
|
+ @rollback="confirmRollback"
|
|
|
+ @inspect="inspectVersion"
|
|
|
+ />
|
|
|
+
|
|
|
+ <v-dialog v-model="jsonDialog" max-width="900">
|
|
|
+ <v-card>
|
|
|
+ <v-card-title>高级 JSON</v-card-title>
|
|
|
+ <v-card-text>
|
|
|
+ <v-alert type="warning" outlined dense>
|
|
|
+ 修改后将覆盖结构化编辑器中的六个本体图分区。
|
|
|
+ </v-alert>
|
|
|
+ <v-textarea
|
|
|
+ v-model="graphJson"
|
|
|
+ label="本体图 JSON"
|
|
|
+ outlined
|
|
|
+ auto-grow
|
|
|
+ rows="18"
|
|
|
+ :readonly="!canEdit"
|
|
|
+ />
|
|
|
+ </v-card-text>
|
|
|
+ <v-card-actions>
|
|
|
+ <v-spacer />
|
|
|
+ <v-btn text @click="jsonDialog = false">关闭</v-btn>
|
|
|
+ <v-btn v-if="canEdit" color="primary" @click="applyJson">应用到编辑器</v-btn>
|
|
|
+ </v-card-actions>
|
|
|
+ </v-card>
|
|
|
+ </v-dialog>
|
|
|
+
|
|
|
+ <v-dialog v-model="publishDialog" max-width="480">
|
|
|
+ <v-card>
|
|
|
+ <v-card-title>发布确认</v-card-title>
|
|
|
+ <v-card-text>
|
|
|
+ 发布后该版本不可修改,并将通过 Outbox 异步投影至语义图。
|
|
|
+ </v-card-text>
|
|
|
+ <v-card-actions>
|
|
|
+ <v-spacer />
|
|
|
+ <v-btn text @click="publishDialog = false">取消</v-btn>
|
|
|
+ <v-btn color="primary" :loading="publishing" @click="publish">
|
|
|
+ 确认发布
|
|
|
+ </v-btn>
|
|
|
+ </v-card-actions>
|
|
|
+ </v-card>
|
|
|
+ </v-dialog>
|
|
|
+
|
|
|
+ <v-dialog v-model="importDialog" max-width="560">
|
|
|
+ <v-card>
|
|
|
+ <v-card-title>导入本体</v-card-title>
|
|
|
+ <v-card-text>
|
|
|
+ <v-file-input
|
|
|
+ v-model="importFile"
|
|
|
+ accept=".json,.owl,.rdf,.xml"
|
|
|
+ label="选择 JSON 或 OWL/RDF 文件"
|
|
|
+ outlined
|
|
|
+ />
|
|
|
+ <v-alert type="info" text dense>
|
|
|
+ 导入会创建一个新的本体及草稿版本,不会覆盖当前本体。
|
|
|
+ </v-alert>
|
|
|
+ </v-card-text>
|
|
|
+ <v-card-actions>
|
|
|
+ <v-spacer />
|
|
|
+ <v-btn text @click="importDialog = false">取消</v-btn>
|
|
|
+ <v-btn color="primary" :disabled="!importFile" :loading="importing" @click="importDocument">
|
|
|
+ 开始导入
|
|
|
+ </v-btn>
|
|
|
+ </v-card-actions>
|
|
|
+ </v-card>
|
|
|
+ </v-dialog>
|
|
|
+
|
|
|
+ <suggestion-review-dialog
|
|
|
+ v-model="suggestionDialog"
|
|
|
+ :change-set-uid="changeSetUid"
|
|
|
+ :suggestions="suggestions"
|
|
|
+ :loading="suggestionLoading"
|
|
|
+ @submit="reviewSuggestions"
|
|
|
+ />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { publishOntology, saveOntologyGraph, validateOntology } from '@/api/dataDevelopment'
|
|
|
+import { saveAs } from 'file-saver'
|
|
|
+
|
|
|
+import { api as governanceApi } from '@/api/dataGovernance'
|
|
|
+import {
|
|
|
+ diffOntology,
|
|
|
+ exportOntology,
|
|
|
+ generateOntologySuggestions,
|
|
|
+ getDataElements,
|
|
|
+ getOntology,
|
|
|
+ getOntologyGraph,
|
|
|
+ getOntologyVersions,
|
|
|
+ importOntology,
|
|
|
+ publishOntology,
|
|
|
+ reviewOntologyChangeSet,
|
|
|
+ rollbackOntology,
|
|
|
+ saveOntologyGraph,
|
|
|
+ validateOntology
|
|
|
+} from '@/api/dataDevelopment'
|
|
|
+
|
|
|
+import GraphSectionEditor from './components/GraphSectionEditor'
|
|
|
+import SuggestionReviewDialog from './components/SuggestionReviewDialog'
|
|
|
+import VersionWorkspace from './components/VersionWorkspace'
|
|
|
+import {
|
|
|
+ applySuggestionDecisions,
|
|
|
+ canEditOntology,
|
|
|
+ canPublishOntology,
|
|
|
+ emptyGraph,
|
|
|
+ normalizeGraph,
|
|
|
+ removeGraphItem,
|
|
|
+ upsertGraphItem
|
|
|
+} from './model'
|
|
|
|
|
|
export default {
|
|
|
name: 'OntologyWorkbench',
|
|
|
- data: () => ({ graphJson: '{\n "classes": [],\n "properties": [],\n "relations": [],\n "constraints": [],\n "domain_links": [],\n "element_mappings": []\n}', revision: 0, issues: [], diff: {}, publishDialog: false }),
|
|
|
+ components: {
|
|
|
+ GraphSectionEditor,
|
|
|
+ SuggestionReviewDialog,
|
|
|
+ VersionWorkspace
|
|
|
+ },
|
|
|
+ data: () => ({
|
|
|
+ ontology: {},
|
|
|
+ graph: emptyGraph(),
|
|
|
+ revision: 0,
|
|
|
+ versions: [],
|
|
|
+ issues: [],
|
|
|
+ diff: {},
|
|
|
+ hasValidated: false,
|
|
|
+ selectedSection: 'classes',
|
|
|
+ domainOptions: [],
|
|
|
+ domainRecords: [],
|
|
|
+ dataElementOptions: [],
|
|
|
+ dataElementRecords: [],
|
|
|
+ saving: false,
|
|
|
+ validating: false,
|
|
|
+ publishing: false,
|
|
|
+ versionLoading: false,
|
|
|
+ suggestionLoading: false,
|
|
|
+ importing: false,
|
|
|
+ publishDialog: false,
|
|
|
+ jsonDialog: false,
|
|
|
+ importDialog: false,
|
|
|
+ suggestionDialog: false,
|
|
|
+ importFile: null,
|
|
|
+ graphJson: '',
|
|
|
+ changeSetUid: '',
|
|
|
+ suggestions: [],
|
|
|
+ sections: [
|
|
|
+ { text: '概念', value: 'classes', icon: 'mdi-shape-outline' },
|
|
|
+ { text: '属性', value: 'properties', icon: 'mdi-format-list-bulleted-type' },
|
|
|
+ { text: '关系', value: 'relations', icon: 'mdi-vector-line' },
|
|
|
+ { text: '约束', value: 'constraints', icon: 'mdi-shield-check-outline' },
|
|
|
+ { text: '业务域', value: 'domain_links', icon: 'mdi-domain' },
|
|
|
+ { text: '数据元素映射', value: 'element_mappings', icon: 'mdi-link-variant' }
|
|
|
+ ]
|
|
|
+ }),
|
|
|
+ computed: {
|
|
|
+ permissions () {
|
|
|
+ return (this.$store.state.user.userInfo || {}).permissions || []
|
|
|
+ },
|
|
|
+ canEdit () {
|
|
|
+ return canEditOntology(this.permissions)
|
|
|
+ },
|
|
|
+ canPublish () {
|
|
|
+ return canPublishOntology(this.permissions)
|
|
|
+ },
|
|
|
+ latestVersionLabel () {
|
|
|
+ return this.versions.length
|
|
|
+ ? `v${this.versions[0].version} · ${this.versions[0].status}`
|
|
|
+ : '尚无版本'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created () {
|
|
|
+ this.loadOntology()
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ '$route.params.uid' (uid, previousUid) {
|
|
|
+ if (uid !== previousUid) this.loadOntology()
|
|
|
+ }
|
|
|
+ },
|
|
|
methods: {
|
|
|
- async save () { await saveOntologyGraph(this.$route.params.uid, JSON.parse(this.graphJson), this.revision); this.revision += 1 },
|
|
|
- async validate () { this.issues = (await validateOntology(this.$route.params.uid)).data || [] },
|
|
|
- async publish () { await publishOntology(this.$route.params.uid, `${this.$route.params.uid}:${this.revision}`); this.publishDialog = false }
|
|
|
+ async loadOntology () {
|
|
|
+ try {
|
|
|
+ const uid = this.$route.params.uid
|
|
|
+ const [detail, graph, versions, domains, elements] = await Promise.all([
|
|
|
+ getOntology(uid),
|
|
|
+ getOntologyGraph(uid),
|
|
|
+ getOntologyVersions(uid),
|
|
|
+ governanceApi.getBusinessDomainList({ current: 1, size: 200, type: 'all' }),
|
|
|
+ getDataElements({ status: 'published' })
|
|
|
+ ])
|
|
|
+ this.ontology = detail.data
|
|
|
+ this.revision = Number(detail.data.draft_revision || 0)
|
|
|
+ this.graph = normalizeGraph(graph.data.graph_document)
|
|
|
+ this.versions = versions.data || []
|
|
|
+ this.domainRecords = domains.data.records || []
|
|
|
+ this.domainOptions = this.domainRecords
|
|
|
+ .map(item => ({
|
|
|
+ text: `${item.name_zh || item.name || item.name_en || '未命名业务域'} · ${item.uid || item.governance_uid || item.id}`,
|
|
|
+ value: String(item.uid || item.governance_uid || item.id)
|
|
|
+ }))
|
|
|
+ .filter(item => item.value && item.value !== 'undefined')
|
|
|
+ this.dataElementRecords = (elements.data || {}).records || []
|
|
|
+ this.dataElementOptions = this.dataElementRecords.map(item => ({
|
|
|
+ text: `${item.snapshot.name_zh || item.snapshot.name_en || item.code} · ${item.uid}`,
|
|
|
+ value: item.uid
|
|
|
+ }))
|
|
|
+ this.hasValidated = false
|
|
|
+ this.issues = []
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async loadVersions () {
|
|
|
+ const response = await getOntologyVersions(this.$route.params.uid)
|
|
|
+ this.versions = response.data || []
|
|
|
+ },
|
|
|
+ upsertItem ({ section, item }) {
|
|
|
+ this.graph = upsertGraphItem(this.graph, section, item)
|
|
|
+ this.hasValidated = false
|
|
|
+ },
|
|
|
+ removeItem ({ section, item }) {
|
|
|
+ this.graph = removeGraphItem(this.graph, section, item)
|
|
|
+ this.hasValidated = false
|
|
|
+ },
|
|
|
+ async save () {
|
|
|
+ this.saving = true
|
|
|
+ try {
|
|
|
+ await saveOntologyGraph(this.$route.params.uid, this.graph, this.revision)
|
|
|
+ this.revision += 1
|
|
|
+ await this.loadVersions()
|
|
|
+ this.hasValidated = false
|
|
|
+ this.$snackbar.success('草稿保存成功')
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(`草稿保存失败:${error}`)
|
|
|
+ await this.loadOntology()
|
|
|
+ } finally {
|
|
|
+ this.saving = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async validate () {
|
|
|
+ this.validating = true
|
|
|
+ try {
|
|
|
+ const response = await validateOntology(this.$route.params.uid)
|
|
|
+ this.issues = response.data || []
|
|
|
+ this.hasValidated = true
|
|
|
+ if (!this.issues.length) this.$snackbar.success('本体校验通过')
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ } finally {
|
|
|
+ this.validating = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async publish () {
|
|
|
+ this.publishing = true
|
|
|
+ try {
|
|
|
+ await publishOntology(
|
|
|
+ this.$route.params.uid,
|
|
|
+ `${this.$route.params.uid}:${this.revision}`
|
|
|
+ )
|
|
|
+ this.publishDialog = false
|
|
|
+ await this.loadOntology()
|
|
|
+ this.$snackbar.success('本体发布成功')
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ } finally {
|
|
|
+ this.publishing = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async compareVersions ({ left, right }) {
|
|
|
+ this.versionLoading = true
|
|
|
+ try {
|
|
|
+ this.diff = (await diffOntology(this.$route.params.uid, left, right)).data || {}
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ } finally {
|
|
|
+ this.versionLoading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ inspectVersion (version) {
|
|
|
+ this.graph = normalizeGraph(version.graph_document)
|
|
|
+ this.hasValidated = false
|
|
|
+ this.$snackbar.success(`已在编辑器中载入 v${version.version} 快照`)
|
|
|
+ },
|
|
|
+ confirmRollback (version) {
|
|
|
+ this.$confirm(
|
|
|
+ '回滚确认',
|
|
|
+ `将从 v${version.version} 创建新的回滚草稿,是否继续?`
|
|
|
+ ).then(() => this.rollback(version))
|
|
|
+ },
|
|
|
+ async rollback (version) {
|
|
|
+ this.versionLoading = true
|
|
|
+ try {
|
|
|
+ await rollbackOntology(this.$route.params.uid, {
|
|
|
+ target_version_uid: version.uid,
|
|
|
+ expected_revision: this.revision
|
|
|
+ })
|
|
|
+ await this.loadOntology()
|
|
|
+ this.$snackbar.success('已创建回滚草稿,请校验后重新发布')
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ } finally {
|
|
|
+ this.versionLoading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ openJsonEditor () {
|
|
|
+ this.graphJson = JSON.stringify(this.graph, null, 2)
|
|
|
+ this.jsonDialog = true
|
|
|
+ },
|
|
|
+ applyJson () {
|
|
|
+ try {
|
|
|
+ this.graph = normalizeGraph(JSON.parse(this.graphJson))
|
|
|
+ this.jsonDialog = false
|
|
|
+ this.hasValidated = false
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error('本体图必须是合法 JSON')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ suggestionPayload () {
|
|
|
+ const domainByUid = new Map(
|
|
|
+ this.domainRecords.map(item => [
|
|
|
+ String(item.uid || item.governance_uid || item.id),
|
|
|
+ item
|
|
|
+ ])
|
|
|
+ )
|
|
|
+ const domains = this.graph.domain_links.map(link => {
|
|
|
+ const domain = domainByUid.get(String(link.domain_uid)) || {}
|
|
|
+ return {
|
|
|
+ uid: String(link.domain_uid),
|
|
|
+ name: domain.name_zh || domain.name || domain.name_en || link.domain_uid
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const dataElements = this.dataElementRecords.map(item => ({
|
|
|
+ uid: item.uid,
|
|
|
+ name: item.snapshot.name_zh || item.snapshot.name_en || item.code,
|
|
|
+ aliases: item.snapshot.aliases || [],
|
|
|
+ status: item.status
|
|
|
+ }))
|
|
|
+ return { domains, data_elements: dataElements, foreign_keys: [], include_ai: false }
|
|
|
+ },
|
|
|
+ async generateSuggestions () {
|
|
|
+ this.suggestionLoading = true
|
|
|
+ try {
|
|
|
+ const response = await generateOntologySuggestions(
|
|
|
+ this.$route.params.uid,
|
|
|
+ this.suggestionPayload()
|
|
|
+ )
|
|
|
+ this.changeSetUid = response.data.change_set_uid
|
|
|
+ this.suggestions = response.data.suggestions || []
|
|
|
+ this.suggestionDialog = true
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ } finally {
|
|
|
+ this.suggestionLoading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async reviewSuggestions (decisions) {
|
|
|
+ this.suggestionLoading = true
|
|
|
+ try {
|
|
|
+ await reviewOntologyChangeSet(
|
|
|
+ this.$route.params.uid,
|
|
|
+ this.changeSetUid,
|
|
|
+ decisions
|
|
|
+ )
|
|
|
+ this.graph = applySuggestionDecisions(
|
|
|
+ this.graph,
|
|
|
+ this.suggestions,
|
|
|
+ decisions
|
|
|
+ )
|
|
|
+ this.suggestionDialog = false
|
|
|
+ this.hasValidated = false
|
|
|
+ this.$snackbar.success('建议评审完成,已应用到当前编辑草稿')
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ } finally {
|
|
|
+ this.suggestionLoading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async exportDocument (format) {
|
|
|
+ try {
|
|
|
+ const response = await exportOntology(this.$route.params.uid, format)
|
|
|
+ saveAs(response.data, response.name || `${this.ontology.code}.${format}`)
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async importDocument () {
|
|
|
+ this.importing = true
|
|
|
+ try {
|
|
|
+ const extension = this.importFile.name.split('.').pop().toLowerCase()
|
|
|
+ const format = extension === 'json' ? 'json' : 'owl'
|
|
|
+ const formData = new FormData()
|
|
|
+ formData.append('file', this.importFile)
|
|
|
+ const response = await importOntology(formData, format)
|
|
|
+ this.importDialog = false
|
|
|
+ this.$router.push(`/data-governance/ontology/${response.data.ontology_uid}`)
|
|
|
+ } catch (error) {
|
|
|
+ this.$snackbar.error(error)
|
|
|
+ } finally {
|
|
|
+ this.importing = false
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.ontology-workbench {
|
|
|
+ background: #f5f7fa;
|
|
|
+ min-height: 100%;
|
|
|
+}
|
|
|
+.workbench-header {
|
|
|
+ min-height: 58px;
|
|
|
+ padding: 0 4px;
|
|
|
+}
|
|
|
+.section-nav,
|
|
|
+.validation-panel {
|
|
|
+ min-height: 520px;
|
|
|
+}
|
|
|
+</style>
|