| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- import { writeFileSync } from 'node:fs';
- import { fileURLToPath } from 'node:url';
- import path from 'node:path';
- const vuePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../src/views/crm/addWx/index.vue');
- const sqlPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../java/sql/add_crm_add_wx_menu_tenant.sql');
- const migrationPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../java/fs-service/src/main/resources/db/tenant-add-wx-client-fail-time-migration.sql');
- const vue = `<template>
- <div class="app-container">
- <el-row class="baseInfo list-stats-row mb8">
- <el-col>
- <el-card shadow="hover" class="stat-card">
- <div slot="header" class="card-header">
- <span>${'\u52A0\u5FAE\u4EFB\u52A1\u603B\u6570'}</span>
- </div>
- <div class="content">
- <span class="card-number total">
- <count-to :start-val="0" :end-val="count.totalNum || 0" :duration="2000" />
- </span>
- </div>
- </el-card>
- </el-col>
- <el-col>
- <el-card shadow="hover" class="stat-card">
- <div slot="header" class="card-header">
- <span>${'\u52A0\u5FAE\u4E2D'}</span>
- </div>
- <div class="content">
- <span class="card-number adding">
- <count-to :start-val="0" :end-val="count.addingNum || 0" :duration="2000" />
- </span>
- </div>
- </el-card>
- </el-col>
- <el-col>
- <el-card shadow="hover" class="stat-card">
- <div slot="header" class="card-header">
- <span>${'\u4ECA\u65E5\u52A0\u5FAE\u6210\u529F'}</span>
- </div>
- <div class="content">
- <span class="card-number success">
- <count-to :start-val="0" :end-val="count.toDayAddNum || 0" :duration="2000" />
- </span>
- </div>
- </el-card>
- </el-col>
- <el-col>
- <el-card shadow="hover" class="stat-card">
- <div slot="header" class="card-header">
- <span>${'\u4ECA\u65E5\u52A0\u5FAE\u5931\u8D25'}</span>
- </div>
- <div class="content">
- <span class="card-number fail">
- <count-to :start-val="0" :end-val="count.toDayFailNum || 0" :duration="2000" />
- </span>
- </div>
- </el-card>
- </el-col>
- </el-row>
- <el-form
- v-show="showSearch"
- ref="queryForm"
- :model="queryParams"
- :inline="true"
- label-width="88px"
- class="list-search-form"
- >
- <el-form-item label="${'\u5BA2\u6237\u540D\u79F0'}" prop="customerName">
- <el-input
- v-model="queryParams.customerName"
- placeholder="${'\u8BF7\u8F93\u5165\u5BA2\u6237\u540D\u79F0'}"
- clearable
- size="small"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="${'\u624B\u673A\u53F7'}" prop="phone">
- <el-input
- v-model="queryParams.phone"
- placeholder="${'\u8BF7\u8F93\u5165\u624B\u673A\u53F7'}"
- clearable
- size="small"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="${'\u52A0\u5FAE\u9500\u552E'}" prop="accountId">
- <el-select v-model="queryParams.accountId" filterable clearable placeholder="${'\u5168\u90E8'}" size="small">
- <el-option
- v-for="item in accountList"
- :key="item.id"
- :label="formatAccountLabel(item)"
- :value="item.id"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="${'\u5916\u547C\u4EFB\u52A1'}" prop="roboticId">
- <el-select v-model="queryParams.roboticId" filterable clearable placeholder="${'\u5168\u90E8'}" size="small">
- <el-option v-for="item in roboticList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </el-form-item>
- <el-form-item label="${'\u52A0\u5FAE\u7C7B\u578B'}" prop="isWeCom">
- <el-select v-model="queryParams.isWeCom" clearable placeholder="${'\u5168\u90E8'}" size="small">
- <el-option label="${'\u4E2A\u5FAE'}" :value="1" />
- <el-option label="${'\u4F01\u5FAE'}" :value="2" />
- </el-select>
- </el-form-item>
- <el-form-item label="${'\u52A0\u5FAE\u72B6\u6001'}" prop="isAdd">
- <el-select v-model="queryParams.isAdd" clearable placeholder="${'\u5168\u90E8'}" size="small">
- <el-option label="${'\u672A\u6DFB\u52A0'}" :value="0" />
- <el-option label="${'\u52A0\u5FAE\u4E2D'}" :value="2" />
- <el-option label="${'\u52A0\u5FAE\u6210\u529F'}" :value="1" />
- <el-option label="${'\u52A0\u5FAE\u5931\u8D25'}" :value="3" />
- </el-select>
- </el-form-item>
- <el-form-item label="${'\u53D1\u8D77\u65F6\u95F4'}" prop="time">
- <el-date-picker
- v-model="queryParams.time"
- type="daterange"
- range-separator="${'\u81F3'}"
- value-format="yyyy-MM-dd"
- start-placeholder="${'\u5F00\u59CB\u65E5\u671F'}"
- end-placeholder="${'\u7ED3\u675F\u65E5\u671F'}"
- size="small"
- />
- </el-form-item>
- <el-form-item class="list-search-actions">
- <el-button type="cyan" 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
- v-hasPermi="['company:companyClient:export']"
- type="warning"
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- >${'\u5BFC\u51FA'}</el-button>
- <right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
- </el-form-item>
- </el-form>
- <el-table v-loading="loading" :data="list" border>
- <el-table-column label="${'\u5BA2\u6237\u540D\u79F0'}" align="center" min-width="120" show-overflow-tooltip>
- <template slot-scope="scope">
- <el-link
- v-if="scope.row.customerId"
- type="primary"
- :underline="false"
- @click="openCustomerDetail(scope.row)"
- >{{ scope.row.customerName || scope.row.nickName || '-' }}</el-link>
- <span v-else>{{ scope.row.customerName || scope.row.nickName || '-' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="${'\u624B\u673A\u53F7'}" align="center" prop="phone" width="130" />
- <el-table-column label="${'\u5916\u547C\u4EFB\u52A1'}" align="center" prop="roboticName" min-width="140" show-overflow-tooltip />
- <el-table-column label="${'\u52A0\u5FAE\u9500\u552E'}" align="center" min-width="120" show-overflow-tooltip>
- <template slot-scope="scope">
- {{ scope.row.companyUserName || '-' }}
- </template>
- </el-table-column>
- <el-table-column label="${'\u52A0\u5FAE\u5FAE\u4FE1\u53F7'}" align="center" prop="wxNickName" min-width="120" show-overflow-tooltip />
- <el-table-column label="${'\u52A0\u5FAE\u7C7B\u578B'}" align="center" width="90">
- <template slot-scope="scope">
- <el-tag v-if="scope.row.isWeCom == 1" type="success" size="mini">${'\u4E2A\u5FAE'}</el-tag>
- <el-tag v-else-if="scope.row.isWeCom == 2" type="primary" size="mini">${'\u4F01\u5FAE'}</el-tag>
- <span v-else>-</span>
- </template>
- </el-table-column>
- <el-table-column label="${'\u52A0\u5FAE\u72B6\u6001'}" align="center" width="100">
- <template slot-scope="scope">
- <el-tag :type="getIsAddType(scope.row.isAdd)" size="mini">{{ getIsAddLabel(scope.row.isAdd) }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="${'\u5BA2\u6237\u610F\u5411'}" align="center" width="100">
- <template slot-scope="scope">
- <span v-for="item in levelList" :key="item.dictValue">
- <el-tag v-if="scope.row.intention == item.dictValue" size="mini">{{ item.dictLabel }}</el-tag>
- </span>
- </template>
- </el-table-column>
- <el-table-column label="${'\u8BDD\u672F'}" align="center" prop="dialogName" min-width="120" show-overflow-tooltip />
- <el-table-column label="${'\u53D1\u8D77\u65F6\u95F4'}" align="center" width="160">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.addTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="${'\u6210\u529F\u65F6\u95F4'}" align="center" width="160">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.successAddTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="${'\u5931\u8D25\u65F6\u95F4'}" align="center" width="160">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.failAddTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
- </template>
- </el-table-column>
- </el-table>
- <pagination
- v-show="total > 0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
- <el-drawer size="75%" :title="customerDrawer.title" :visible.sync="customerDrawer.open">
- <customer-details ref="customerDetails" />
- </el-drawer>
- </div>
- </template>
- <script>
- import { listCompanyClient, addWxStatistics, exportCompanyClient } from '@/api/company/companyClient'
- import { listAll as roboticListAll } from '@/api/company/companyVoiceRobotic'
- import { listAll as accountListAll } from '@/api/company/companyAccount'
- import { getDicts } from '@/api/system/dict/data'
- import CountTo from 'vue-count-to'
- import customerDetails from '../components/customerDetails.vue'
- export default {
- name: 'CrmAddWxProgress',
- components: { CountTo, customerDetails },
- data() {
- return {
- loading: false,
- showSearch: true,
- total: 0,
- list: [],
- roboticList: [],
- accountList: [],
- levelList: [],
- count: {},
- customerDrawer: {
- title: '${'\u5BA2\u6237\u8BE6\u60C5'}',
- open: false
- },
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- customerName: null,
- phone: null,
- accountId: null,
- roboticId: null,
- isWeCom: null,
- isAdd: null,
- time: []
- }
- }
- },
- created() {
- this.initOptions()
- this.handleQuery()
- },
- methods: {
- initOptions() {
- roboticListAll().then(res => {
- this.roboticList = res.data || []
- })
- accountListAll().then(res => {
- this.accountList = res.data || []
- })
- getDicts('customer_intention_level').then(res => {
- this.levelList = res.data || []
- })
- },
- formatAccountLabel(item) {
- const userName = item.companyUserName || item.nickName || ''
- const wxName = item.wxNickName || ''
- if (userName && wxName) {
- return userName + '-' + wxName
- }
- return userName || wxName || '-'
- },
- getQueryData() {
- const params = JSON.parse(JSON.stringify(this.queryParams))
- if (params.time && params.time.length === 2) {
- params.beginTime = params.time[0]
- params.endTime = params.time[1]
- }
- delete params.time
- return params
- },
- getList() {
- this.loading = true
- listCompanyClient(this.getQueryData())
- .then(response => {
- this.list = response.rows || []
- this.total = response.total || 0
- })
- .finally(() => {
- this.loading = false
- })
- },
- loadStatistics() {
- addWxStatistics(this.getQueryData()).then(res => {
- this.count = res || {}
- })
- },
- getIsAddLabel(value) {
- if (value === 0) return '${'\u672A\u6DFB\u52A0'}'
- if (value === 1) return '${'\u52A0\u5FAE\u6210\u529F'}'
- if (value === 2) return '${'\u52A0\u5FAE\u4E2D'}'
- if (value === 3) return '${'\u52A0\u5FAE\u5931\u8D25'}'
- return '-'
- },
- getIsAddType(value) {
- if (value === 0) return 'info'
- if (value === 1) return 'success'
- if (value === 2) return 'warning'
- if (value === 3) return 'danger'
- return 'info'
- },
- handleQuery() {
- this.queryParams.pageNum = 1
- this.loadStatistics()
- this.getList()
- },
- resetQuery() {
- this.resetForm('queryForm')
- this.handleQuery()
- },
- openCustomerDetail(row) {
- if (!row || !row.customerId) {
- return
- }
- this.customerDrawer.open = true
- const that = this
- setTimeout(() => {
- if (that.$refs.customerDetails) {
- that.$refs.customerDetails.initDuplicate(row.isDuplicate, row.dcustomerId)
- that.$refs.customerDetails.getDetails(row.customerId)
- }
- }, 200)
- },
- handleExport() {
- this.$confirm('${'\u662F\u5426\u786E\u8BA4\u5BFC\u51FA\u5F53\u524D\u7B5B\u9009\u6761\u4EF6\u4E0B\u7684\u52A0\u5FAE\u8FDB\u5EA6\u6570\u636E\uFF1F'}', '${'\u8B66\u544A'}', {
- confirmButtonText: '${'\u786E\u5B9A'}',
- cancelButtonText: '${'\u53D6\u6D88'}',
- type: 'warning'
- }).then(() => {
- return exportCompanyClient(this.getQueryData())
- }).then(response => {
- this.download(response.msg)
- }).catch(() => {})
- }
- }
- }
- </script>
- <style rel="stylesheet/scss" lang="scss" scoped>
- .baseInfo {
- margin-bottom: 16px;
- }
- .list-stats-row {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- .el-col {
- flex: 1;
- min-width: 200px;
- max-width: 320px;
- }
- }
- .stat-card {
- .card-header {
- font-size: 14px;
- color: #606266;
- }
- .card-number {
- display: inline-block;
- font-size: 28px;
- font-weight: 600;
- line-height: 1.2;
- }
- .total {
- color: #409eff;
- }
- .adding {
- color: #e6a23c;
- }
- .success {
- color: #67c23a;
- }
- .fail {
- color: #f56c6c;
- }
- }
- </style>
- `;
- const migration = `-- ${'\u79DF\u6237\u5E93\uFF1A\u52A0\u5FAE\u5931\u8D25\u65F6\u95F4\u5B57\u6BB5\uFF08MySQL 5.7+\uFF0C\u82E5\u5DF2\u5B58\u5728\u8BF7\u5FFD\u7565\u62A5\u9519\uFF09'}
- ALTER TABLE company_wx_client
- ADD COLUMN fail_add_time datetime NULL DEFAULT NULL COMMENT '${'\u52A0\u5FAE\u5931\u8D25\u65F6\u95F4'}' AFTER success_add_time;
- `;
- writeFileSync(vuePath, vue, 'utf8');
- writeFileSync(migrationPath, migration, 'utf8');
- console.log('UTF-8 files written:', vuePath, migrationPath);
|