jcloud/dashboard/src2/components/devtools/database/DatabaseTableSchemaDialog.vue
2025-04-12 17:39:38 +08:00

213 lines
4.5 KiB
Vue

<template>
<Dialog
:options="{
title: '浏览表结构',
size: '2xl'
}"
>
<template #body-content>
<p class="mb-2 text-sm text-gray-700">选择表</p>
<div class="flex flex-row gap-2">
<FormControl
class="w-full"
type="autocomplete"
:options="autocompleteOptions"
v-model="selectedSchema"
/>
<Button
icon="copy"
@click="copyTableNameToClipboard"
v-if="selectedSchema"
/>
</div>
<div
class="mt-3 flex flex-row gap-2"
v-if="selectedSchema && showSQLActions"
>
<Button
iconLeft="play"
class="grow"
variant="outline"
@click="viewTop100Rows"
>查看前100行</Button
>
<Button
iconLeft="play"
class="grow"
variant="outline"
@click="viewLast100Rows"
>查看最后100行</Button
>
<Button
iconLeft="play"
class="grow"
variant="outline"
@click="viewAllRows"
>查看所有行</Button
>
</div>
<ObjectList :options="listOptions" v-if="selectedSchema" />
</template>
</Dialog>
</template>
<script>
import { h } from 'vue';
import { FormControl } from 'jingrow-ui';
import ObjectList from '../../ObjectList.vue';
import { icon } from '../../../utils/components';
import { toast } from 'vue-sonner';
export default {
name: 'DatabaseTableSchemaDialog',
props: {
site: {
type: String,
required: true
},
tableSchemas: {
type: Object,
required: true
},
showSQLActions: {
type: Boolean,
default: false
},
preSelectedSchema: {
type: String,
default: null
}
},
emits: ['runSQLQuery'],
components: {
FormControl,
ObjectList
},
data() {
return {
selectedSchema: null
};
},
mounted() {
this.preSelectSchema();
},
watch: {
preSelectedSchema() {
this.preSelectSchema();
}
},
computed: {
autocompleteOptions() {
return Object.keys(this.tableSchemas).map(x => ({
label:
this.tableSchemas[x].size.total_size > 0.01
? `${x} (${this.bytesToMB(this.tableSchemas[x].size.total_size)}MB)`
: x,
value: x
}));
},
listOptions() {
if (!this.selectedSchema || !this.selectedSchema.value) return {};
return {
data: () => {
return this.tableSchemas?.[this.selectedSchema.value]?.columns ?? [];
},
hideControls: true,
columns: [
{
label: '列名',
fieldname: 'column',
width: 0.5,
type: 'Component',
component({ row }) {
return h(
'div',
{
class: 'truncate text-base cursor-copy',
onClick() {
if ('clipboard' in navigator) {
navigator.clipboard.writeText(row.column);
toast.success('已复制到剪贴板');
}
}
},
[row.column]
);
}
},
{
label: '数据类型',
fieldname: 'data_type',
width: 0.2,
align: 'center'
},
{
label: '默认值',
fieldname: 'default',
width: 0.3,
align: 'center'
},
{
label: '可为空',
fieldname: 'is_nullable',
width: 0.15,
type: 'Icon',
Icon(value) {
return value ? 'check' : 'x';
},
align: 'center'
},
{
label: '已索引',
width: 0.15,
align: 'center',
type: 'Component',
component({ row }) {
return row.index_info.is_indexed
? icon('check', 'w-4 w-4')
: icon('x', 'w-4 w-4');
}
}
]
};
}
},
methods: {
copyTableNameToClipboard() {
if ('clipboard' in navigator) {
navigator.clipboard.writeText(this.selectedSchema.value);
toast.success('已复制到剪贴板');
}
},
viewTop100Rows() {
this.$emit(
'runSQLQuery',
`SELECT * FROM \`${this.selectedSchema.value}\` LIMIT 100;`
);
},
viewLast100Rows() {
this.$emit(
'runSQLQuery',
`SELECT * FROM \`${this.selectedSchema.value}\` ORDER BY name DESC LIMIT 100;`
);
},
viewAllRows() {
this.$emit(
'runSQLQuery',
`SELECT * FROM \`${this.selectedSchema.value}\`;`
);
},
bytesToMB(bytes) {
return (bytes / (1024 * 1024)).toFixed(2);
},
preSelectSchema() {
if (!this.preSelectedSchema) return;
if (!this.tableSchemas) return;
if (this.autocompleteOptions.length == 0) return;
this.selectedSchema = {
label: this.preSelectedSchema,
value: this.preSelectedSchema
};
}
}
};
</script>