322 lines
17 KiB
HTML
322 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>MarketingSystemDataTool</title>
|
||
<script>
|
||
var __v = window.__ASSET_VERSION__ || String(Date.now());
|
||
var __addCss = function(h){ var l=document.createElement('link'); l.rel='stylesheet'; l.href=h+'?v='+__v; document.head.appendChild(l); };
|
||
__addCss('./vendor/element-plus.min.css');
|
||
__addCss('./styles.css');
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<div id="app">
|
||
<el-container>
|
||
<el-header height="56px">
|
||
<el-row align="middle" justify="space-between">
|
||
<el-col :span="24">
|
||
<div class="title">导出工具</div>
|
||
</el-col>
|
||
</el-row>
|
||
</el-header>
|
||
<el-main>
|
||
<el-row :gutter="16">
|
||
<el-col :span="24">
|
||
<el-card>
|
||
<template #header>
|
||
<div style="display:flex;align-items:center;gap:8px">
|
||
<span>导出模版</span>
|
||
<el-button type="primary" size="small" @click="createVisible=true">新增模板</el-button>
|
||
</div>
|
||
</template>
|
||
<el-table :data="templates" size="small" stripe>
|
||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||
<el-table-column prop="name" label="名称"></el-table-column>
|
||
<el-table-column label="数据源" width="120">
|
||
<template #default="scope">{{ dsLabel(scope.row.datasource) }}</template>
|
||
</el-table-column>
|
||
<el-table-column prop="file_format" label="格式" width="100"></el-table-column>
|
||
<el-table-column prop="field_count" label="字段数" width="100"></el-table-column>
|
||
|
||
<el-table-column label="操作" width="260">
|
||
<template #default="scope">
|
||
<el-button size="small" type="primary" @click="openExport(scope.row)">执行</el-button>
|
||
<el-button size="small" @click="openJobs(scope.row)">任务</el-button>
|
||
<el-button
|
||
v-if="(!hasUserId) || (hasUserId && Number(scope.row.owner_id)===currentUserId)"
|
||
size="small"
|
||
@click="openEdit(scope.row)">编辑</el-button>
|
||
<el-button
|
||
v-if="(!hasUserId) || (Number(scope.row.owner_id)!==0 && Number(scope.row.owner_id)===currentUserId)"
|
||
size="small"
|
||
type="danger"
|
||
@click="removeTemplate(scope.row.id)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<el-dialog v-model="jobsVisible" :title="'导出任务(模板 '+ (jobsTplId||'') +')'" width="1000px">
|
||
<el-table :data="jobs" size="small" stripe row-key="id">
|
||
<el-table-column prop="id" label="ID"></el-table-column>
|
||
<el-table-column label="校验状态">
|
||
<template #default="scope">{{ scope.row.eval_status || '评估中' }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="进度">
|
||
<template #default="scope">{{ jobPercent(scope.row) }}</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="行数">
|
||
<template #default="scope">
|
||
{{ Number(scope.row.row_estimate||0) > 0 ? Number(scope.row.row_estimate||0) : '评估中' }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="total_rows" label="已写行数"></el-table-column>
|
||
<el-table-column prop="file_format" label="格式"></el-table-column>
|
||
<el-table-column label="创建时间">
|
||
<template #default="scope">{{ fmtDT(new Date(scope.row.created_at)) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="200">
|
||
<template #default="scope">
|
||
<el-button size="small" @click="openSQL(scope.row.id)">分析</el-button>
|
||
<el-button v-if="scope.row.status==='completed' && Number(scope.row.total_rows)>0" size="small" type="success" @click="download(scope.row.id)">下载</el-button>
|
||
<el-button v-else-if="scope.row.status==='completed'" size="small" disabled>无数据</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div style="display:flex;justify-content:flex-end;margin-top:8px">
|
||
<el-pagination background layout="prev, pager, next, total" :total="jobsTotal" :page-size="jobsPageSize" v-model:currentPage="jobsPage" @current-change="loadJobs" />
|
||
</div>
|
||
<template #footer>
|
||
<el-button @click="closeJobs">关闭</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
<el-dialog v-model="sqlVisible" title="生成SQL" width="800px">
|
||
<div style="max-height:50vh;overflow:auto"><pre style="white-space:pre-wrap">{{ sqlText }}</pre></div>
|
||
<template #footer>
|
||
<div style="display:flex; align-items:center; justify-content:space-between; gap:12px; width:100%">
|
||
<div style="flex:1; min-width:0; text-align:left; color:#606266">
|
||
<el-text v-if="sqlExplainDesc" type="info" truncated>{{ sqlExplainDesc }}</el-text>
|
||
<el-text v-else type="info">评估中或暂无分析结果</el-text>
|
||
</div>
|
||
<div style="display:flex; gap:8px">
|
||
<el-button @click="sqlVisible=false">关闭</el-button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</el-col>
|
||
</el-row>
|
||
</el-main>
|
||
</el-container>
|
||
<el-dialog v-model="createVisible" title="新增模板" :width="createWidth">
|
||
<el-form ref="createFormRef" :model="form" :rules="createRules" label-width="110px" status-icon>
|
||
<el-form-item label="模板名称" required show-message prop="name"><el-input v-model="form.name" placeholder="模板名称" /></el-form-item>
|
||
<el-form-item label="数据源" required show-message>
|
||
<el-select v-model="form.datasource" placeholder="选择" :teleported="false">
|
||
<el-option v-for="opt in datasourceOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="导出场景" required show-message>
|
||
<el-select v-model="form.main_table" placeholder="订单数据">
|
||
<el-option v-for="opt in sceneOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="订单类型" required show-message prop="orderType">
|
||
<el-radio-group v-model="form.orderType">
|
||
<el-radio v-for="opt in orderTypeOptionsFor(form.datasource)" :key="opt.value" :label="opt.value">{{ opt.label }}</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="字段选择" required show-message prop="fieldsSel">
|
||
<div ref="createCascaderRoot">
|
||
<el-cascader
|
||
ref="fieldsCascader"
|
||
v-model="form.fieldsSel"
|
||
:key="form.datasource + '-' + String(form.orderType)"
|
||
:options="fieldOptionsDynamic"
|
||
:props="{ multiple: true, checkStrictly: false, expandTrigger: 'hover', checkOnClickNode: true, checkOnClickLeaf: true }"
|
||
:teleported="false"
|
||
collapse-tags
|
||
collapse-tags-tooltip
|
||
placeholder="按场景逐级选择,可多选"
|
||
@visible-change="onCascaderVisible('create', $event)"
|
||
@change="onFieldsSelChange('create')"
|
||
/>
|
||
</div>
|
||
</el-form-item>
|
||
|
||
|
||
<el-row :gutter="8">
|
||
<el-col :span="12">
|
||
<el-form-item label="输出格式" required show-message prop="file_format">
|
||
<el-select v-model="form.file_format" :teleported="false" placeholder="请选择" style="width:160px">
|
||
<el-option v-for="opt in formatOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="可见性" required show-message prop="visibility">
|
||
<el-select v-model="form.visibility" clearable :teleported="false" style="width:160px" placeholder="请选择">
|
||
<el-option v-for="opt in visibilityOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="resizeDialog('create', -100)">缩小</el-button>
|
||
<el-button @click="resizeDialog('create', 100)">放大</el-button>
|
||
<el-button @click="createVisible=false">取消</el-button>
|
||
<el-button type="primary" @click="createTemplate">创建</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
<el-dialog v-model="editVisible" title="编辑模板" :width="editWidth">
|
||
<el-form ref="editFormRef" :model="edit" :rules="editRules" label-width="110px">
|
||
<el-form-item label="模板名称" required show-message prop="name"><el-input v-model="edit.name" /></el-input></el-form-item>
|
||
<el-form-item label="数据源">
|
||
<el-select v-model="edit.datasource" placeholder="选择" :teleported="false" style="width:160px">
|
||
<el-option v-for="opt in datasourceOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="导出场景">
|
||
<el-select v-model="edit.main_table" placeholder="订单数据" style="width:160px">
|
||
<el-option v-for="opt in editSceneOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="订单类型" required show-message prop="orderType">
|
||
<el-radio-group v-model="edit.orderType">
|
||
<el-radio v-for="opt in orderTypeOptionsFor(edit.datasource)" :key="opt.value" :label="opt.value">{{ opt.label }}</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="字段选择" required show-message prop="fieldsSel">
|
||
<div ref="editCascaderRoot">
|
||
<el-cascader
|
||
ref="editFieldsCascader"
|
||
v-model="edit.fieldsSel"
|
||
:key="edit.datasource + '-' + String(edit.orderType)"
|
||
:options="editFieldOptionsDynamic"
|
||
:props="{ multiple: true, checkStrictly: false, expandTrigger: 'hover', checkOnClickNode: true, checkOnClickLeaf: true }"
|
||
:teleported="false"
|
||
collapse-tags
|
||
collapse-tags-tooltip
|
||
placeholder="按场景逐级选择,可多选"
|
||
@visible-change="onCascaderVisible('edit', $event)"
|
||
@change="onFieldsSelChange('edit')"
|
||
/>
|
||
</div>
|
||
</el-form-item>
|
||
<el-row :gutter="8">
|
||
<el-col :span="12">
|
||
<el-form-item label="输出格式">
|
||
<el-select v-model="edit.file_format" :teleported="false" placeholder="请选择" style="width:160px">
|
||
<el-option v-for="opt in formatOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="可见性">
|
||
<el-select v-model="edit.visibility" clearable :disabled="hasUserId" :teleported="false" style="width:160px" placeholder="请选择">
|
||
<el-option v-for="opt in visibilityOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="resizeDialog('edit', -100)">缩小</el-button>
|
||
<el-button @click="resizeDialog('edit', 100)">放大</el-button>
|
||
<el-button @click="editVisible=false">取消</el-button>
|
||
<el-button type="primary" @click="saveEdit">保存</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
<el-dialog v-model="exportVisible" :title="exportTitle" width="1100px">
|
||
<el-form ref="exportFormRef" :model="exportForm" :rules="exportRules" label-width="110px" status-icon>
|
||
<div class="section-title">筛选条件</div>
|
||
<el-row :gutter="8">
|
||
<el-col :span="24">
|
||
<el-form-item label="时间范围" required show-message prop="dateRange">
|
||
<el-date-picker v-model="exportForm.dateRange" type="datetimerange" start-placeholder="开始时间" end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="8" v-if="isOrder && exportForm.datasource==='ymt'">
|
||
<el-col :span="8">
|
||
<el-form-item label="创建者" prop="ymtCreatorId">
|
||
<el-select v-model.number="exportForm.ymtCreatorId" :disabled="hasUserId" clearable filterable :teleported="false" placeholder="请选择创建者" style="width:100%">
|
||
<el-option v-for="opt in ymtCreatorOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="客户" prop="ymtMerchantId">
|
||
<el-select v-model.number="exportForm.ymtMerchantId" :disabled="!exportForm.ymtCreatorId" clearable filterable :teleported="false" placeholder="请选择客户" style="width:100%">
|
||
<el-option v-for="opt in ymtMerchantOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="活动" prop="ymtActivityId">
|
||
<el-select v-model.number="exportForm.ymtActivityId" :disabled="!exportForm.ymtMerchantId" clearable filterable :teleported="false" placeholder="请选择活动" style="width:100%">
|
||
<el-option v-for="opt in ymtActivityOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="8" v-if="isOrder && exportForm.datasource==='marketing'">
|
||
<el-col :span="12">
|
||
<el-form-item label="创建者" prop="creator">
|
||
<el-select v-model="exportForm.creatorIds" multiple filterable :disabled="hasUserId" :teleported="false" placeholder="请选择创建者" style="width:100%">
|
||
<el-option v-for="opt in creatorOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="分销商" prop="resellerId">
|
||
<el-select v-model.number="exportForm.resellerId" filterable :teleported="false" placeholder="请选择分销商" style="width:100%" :disabled="!hasCreators">
|
||
<el-option v-for="opt in resellerOptions" :key="opt.value" :label="opt.label||String(opt.value)" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="8" v-if="isOrder && exportForm.datasource==='marketing'">
|
||
<el-col :span="12">
|
||
<el-form-item label="计划" prop="planId">
|
||
<el-select v-model="exportForm.planId" :disabled="!hasReseller" :teleported="false" filterable placeholder="选择计划">
|
||
<el-option v-for="opt in planOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
|
||
<el-row :gutter="8" v-if="isOrder">
|
||
<el-col :span="12" v-if="exportType===2">
|
||
<el-form-item label="立减金批次号" prop="voucherChannelActivityId"><el-input v-model="exportForm.voucherChannelActivityId" placeholder="请输入立减金批次号" /></el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
|
||
<!-- 输出格式按模板设置,不在此显示 -->
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="exportVisible=false">取消</el-button>
|
||
<el-button type="primary" :loading="exportSubmitting" :disabled="exportSubmitting" @click="submitExport">{{ exportSubmitting ? '估算中...' : '执行并分析' }}</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
<script src="./config.js"></script>
|
||
<script>
|
||
(function(){
|
||
var v = window.__ASSET_VERSION__ || String(Date.now());
|
||
function load(src){ return new Promise(function(res, rej){ var s=document.createElement('script'); s.src=src+'?v='+v; s.onload=res; s.onerror=rej; document.body.appendChild(s); }); }
|
||
load('./vendor/vue.global.prod.js').then(function(){ return load('./vendor/element-plus.full.min.js'); }).then(function(){ return load('./main.js'); });
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|