AdwebSiteList.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. <template>
  2. <div class="p-2">
  3. <!--查询区域-->
  4. <div class="jeecg-basic-table-form-container">
  5. <a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
  6. <a-row :gutter="24">
  7. <a-col :xxl="6" :xl="7">
  8. <a-form-item name="name" label="站点名称">
  9. <j-input placeholder="请输入站点名称" v-model:value="queryParam.name" allow-clear />
  10. </a-form-item>
  11. </a-col>
  12. <a-col :xxl="6" :xl="7">
  13. <a-form-item name="domain" label="站点域名">
  14. <j-input placeholder="请输入站点域名" v-model:value="queryParam.domain" allow-clear />
  15. </a-form-item>
  16. </a-col>
  17. <a-col :xxl="6" :xl="8">
  18. <a-form-item label="发布状态">
  19. <j-search-select allow-clear placeholder="请选择发布状态" v-model:value="queryParam.status" dict="site_status" />
  20. </a-form-item>
  21. </a-col>
  22. <a-col v-if="isAdmin" :xxl="6" :xl="7">
  23. <a-form-item label="租户">
  24. <j-search-select
  25. allow-clear
  26. placeholder="请选择租户"
  27. v-model:value="queryParam.channelProviderId"
  28. dict="sys_tenant,name,id,del_flag=0 AND status=1"
  29. />
  30. </a-form-item>
  31. </a-col>
  32. <template v-if="toggleSearchStatus">
  33. <!-- <a-col :xxl="12" :xl="10">-->
  34. <!-- <a-form-item label="创建时间">-->
  35. <!-- <j-range-date placeholder="请选择开始日期" class="query-group-cust" v-model:value="queryParam.ctime" />-->
  36. <!-- </a-form-item>-->
  37. <!-- </a-col>-->
  38. <!-- <a-col :xl="10" :lg="11" :md="12" :sm="24">-->
  39. <!-- <a-form-item label="到期时间">-->
  40. <!-- <j-range-date placeholder="请选择开始日期" class="query-group-cust" v-model:value="queryParam.etime" />-->
  41. <!-- </a-form-item>-->
  42. <!-- </a-col>-->
  43. </template>
  44. <a-col :xl="6" :lg="7" :md="8" :sm="24">
  45. <span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
  46. <a-col :lg="6">
  47. <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
  48. <a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
  49. <a @click="toggleSearchStatus = !toggleSearchStatus" style="margin-left: 8px">
  50. {{ toggleSearchStatus ? '收起' : '展开' }}
  51. <Icon :icon="toggleSearchStatus ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
  52. </a>
  53. </a-col>
  54. </span>
  55. </a-col>
  56. </a-row>
  57. </a-form>
  58. </div>
  59. <!--引用表格-->
  60. <BasicTable @register="registerTable" :rowSelection="rowSelection">
  61. <!--插槽:table标题-->
  62. <template #tableTitle>
  63. <!-- <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>-->
  64. <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
  65. <!-- <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>-->
  66. <!-- <a-dropdown v-if="selectedRowKeys.length > 0">-->
  67. <!-- <template #overlay>-->
  68. <!-- <a-menu>-->
  69. <!-- <a-menu-item key="1" @click="batchHandleDelete">-->
  70. <!-- <Icon icon="ant-design:delete-outlined" />-->
  71. <!-- 删除-->
  72. <!-- </a-menu-item>-->
  73. <!-- </a-menu>-->
  74. <!-- </template>-->
  75. <!-- <a-button-->
  76. <!-- >批量操作-->
  77. <!-- <Icon icon="mdi:chevron-down" />-->
  78. <!-- </a-button>-->
  79. <!-- </a-dropdown>-->
  80. <!-- 高级查询 -->
  81. <super-query :config="superQueryConfig" @search="handleSuperQuery" />
  82. </template>
  83. <!--操作栏-->
  84. <template #action="{ record }">
  85. <TableAction
  86. style="padding: 5px 8px; display: flex; justify-content: space-around"
  87. :actions="getTableAction(record)"
  88. :dropDownActions="getDropDownAction(record)"
  89. />
  90. </template>
  91. <template #bodyCell="{ column, record, index, text }">
  92. <div v-if="column.dataIndex == 'name'">
  93. <a :href="record.domain" target="_blank">{{ text }}</a>
  94. </div>
  95. <div v-if="column.dataIndex == 'domain'">
  96. <a :href="record.domain" target="_blank">{{ text }}</a>
  97. </div>
  98. <div v-if="column.dataIndex == 'subscribePlan'">
  99. <template v-if="text === null || text === ''"> 无 </template>
  100. <template v-else>
  101. <a-popover>
  102. <template #content>
  103. <a-descriptions bordered :column="{ xxl: 1, xl: 1, lg: 1, md: 1, sm: 1, xs: 1 }" title="SEO套餐详情" size="default">
  104. <a-descriptions-item label="套餐名">
  105. {{ text.planName }}
  106. </a-descriptions-item>
  107. <a-descriptions-item label="关键词"> {{ text.keywordCount }}个 </a-descriptions-item>
  108. <a-descriptions-item label="服务时间">
  109. <template v-if="text.serviceTime != 0"> {{ text.serviceTime }}个月 </template>
  110. <template v-else> 长期 </template>
  111. </a-descriptions-item>
  112. <a-descriptions-item label="价格"> {{ text.price }}元 </a-descriptions-item>
  113. </a-descriptions>
  114. </template>
  115. <a-tag color="blue">
  116. {{ text.planName }}
  117. </a-tag>
  118. </a-popover>
  119. </template>
  120. </div>
  121. <div v-if="column.dataIndex == 'status_dictText'">
  122. <template v-if="record.status == 1">
  123. <a-tag color="blue">
  124. {{ text }}
  125. </a-tag>
  126. </template>
  127. <template v-else-if="record.status == 2">
  128. <a-tag color="green">
  129. {{ text }}
  130. </a-tag>
  131. </template>
  132. <template v-else>
  133. <a-tag color="red">
  134. {{ text }}
  135. </a-tag>
  136. </template>
  137. </div>
  138. <div v-if="column.dataIndex == 'siteCurrentStep'">
  139. <span v-if="text === null || text === undefined || text === ''"> - </span>
  140. <template v-else>
  141. <a @click="handleProcess(record, 'site')"> <span class="circle" style="background-color: #7194f8"></span>{{ text }} </a>
  142. </template>
  143. </div>
  144. <div v-if="column.dataIndex == 'completeProcess'">
  145. <a-progress :stroke-color="{ '0%': '#108ee9', '100%': '#87d068' }" :percent="record.completeProcess" />
  146. </div>
  147. </template>
  148. </BasicTable>
  149. <!-- 表单区域 -->
  150. <AdwebSiteModal ref="registerModal" @success="handleSuccess" />
  151. <site-set-enquiry ref="siteSetEnquiryRef" @success="reload" />
  152. <!-- 自动化嵌入GTM 代码 -->
  153. <gtm-add ref="gtmRef" />
  154. <!--SEO流程-->
  155. <seo-process ref="seoProcessRef" :visible="seoProcessVisible" :title="processTitle" @close="closeProcess" @reload="reload" />
  156. <google-ads-modal ref="googleAdsModalRef" @success="reload" />
  157. <Sohoeb2bOrder ref="sohoeb2bOrderRef" @reload="reload" />
  158. <SiteRelease ref="siteReleaseRef" @reload="reload" />
  159. </div>
  160. </template>
  161. <script lang="ts" name="adweb-adwebSite" setup>
  162. import { computed, onBeforeMount, reactive, ref } from 'vue';
  163. import { BasicTable, TableAction } from '/src/components/Table';
  164. import { useListPage } from '/src/hooks/system/useListPage';
  165. import { columns, superQuerySchema } from './AdwebSite.data';
  166. import { batchDelete, deleteOne, getExportUrl, getImportUrl, list, saveOrUpdate } from './AdwebSite.api';
  167. import AdwebSiteModal from './components/AdwebSiteModal.vue';
  168. import { useUserStore } from '/src/store/modules/user';
  169. import SeoProcess from '@/views/adweb/site/components/SeoProcess.vue';
  170. import JInput from '@/components/Form/src/jeecg/components/JInput.vue';
  171. import JSearchSelect from '@/components/Form/src/jeecg/components/JSearchSelect.vue';
  172. import GtmAdd from '@/views/adweb/site/components/GtmAdd.vue';
  173. import { RoleEnum } from '@/enums/roleEnum';
  174. import { useMessage } from '@/hooks/web/useMessage';
  175. import SiteSetEnquiry from '@/views/adweb/site/components/SiteSetEnquiry.vue';
  176. import GoogleAdsModal from './components/GoogleAdsModal.vue';
  177. import { getAuthCache } from '@/utils/auth';
  178. import { TENANT_ID } from '@/enums/cacheEnum';
  179. import { getTenantById } from '@/views/system/tenant/tenant.api';
  180. import Sohoeb2bOrder from '@/views/adweb/site/components/Sohoeb2bOrder.vue';
  181. import SiteRelease from '@/views/adweb/site/components/SiteRelease.vue';
  182. const formRef = ref();
  183. const queryParam = reactive<any>({});
  184. const toggleSearchStatus = ref<boolean>(false);
  185. const registerModal = ref();
  186. const userStore = useUserStore();
  187. const processTitle = ref('');
  188. const seoProcessVisible = ref(false);
  189. const seoProcessRef = ref();
  190. const sohoeb2bOrderRef = ref();
  191. const siteReleaseRef = ref();
  192. const gtmRef = ref();
  193. const siteSetEnquiryRef = ref();
  194. const googleAdsModalRef = ref();
  195. // admin 判断和后端保持一致
  196. // src/main/java/org/jeecg/modules/adweb/system/service/impl/SysAdwebApiImpl.java L60
  197. // TODO 将此判断加入store,方便所有组件全局调用
  198. console.log(userStore.getRoleList, '当前用户所属角色');
  199. const isAdmin = computed(() => {
  200. return (
  201. userStore.getRoleList.includes(RoleEnum.ADMIN) ||
  202. userStore.getRoleList.includes(RoleEnum.ADWEB_ADMIN) ||
  203. userStore.getRoleList.includes(RoleEnum.SEO_ADMIN) ||
  204. userStore.getRoleList.includes(RoleEnum.ADWEB_SITE_MANAGER) ||
  205. userStore.getRoleList.includes(RoleEnum.ADWEB_SEO_MANAGER)
  206. );
  207. });
  208. // 租户管理员角色
  209. const isTenantAdmin = computed(() => {
  210. return userStore.getRoleList.includes(RoleEnum.ADWEB_CHANNEL_ADMIN);
  211. });
  212. // 是否是苏豪纺织的租户
  213. const isSohoeb2b = ref(false);
  214. const { createMessage } = useMessage();
  215. //注册table数据
  216. const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
  217. tableProps: {
  218. title: 'adweb站点配置表单',
  219. api: list,
  220. columns,
  221. canResize: false,
  222. useSearchForm: true,
  223. showTableSetting: true,
  224. actionColumn: {
  225. width: 180,
  226. fixed: 'right',
  227. },
  228. beforeFetch: (params) => {
  229. return Object.assign(params, queryParam);
  230. },
  231. },
  232. exportConfig: {
  233. name: 'adweb站点配置表单',
  234. url: getExportUrl,
  235. params: queryParam,
  236. },
  237. importConfig: {
  238. url: getImportUrl,
  239. success: handleSuccess,
  240. },
  241. });
  242. const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] =
  243. tableContext;
  244. const labelCol = reactive({
  245. xs: 24,
  246. sm: 4,
  247. xl: 6,
  248. xxl: 4,
  249. });
  250. const wrapperCol = reactive({
  251. xs: 24,
  252. sm: 20,
  253. });
  254. // 高级查询配置
  255. const superQueryConfig = reactive(superQuerySchema);
  256. onBeforeMount(async () => {
  257. isSohoeb2bTenant();
  258. });
  259. /**
  260. * 高级查询事件
  261. */
  262. function handleSuperQuery(params) {
  263. Object.keys(params).map((k) => {
  264. queryParam[k] = params[k];
  265. });
  266. searchQuery();
  267. }
  268. /**
  269. * 新增事件
  270. */
  271. function handleAdd() {
  272. registerModal.value.disableSubmit = false;
  273. registerModal.value.add();
  274. }
  275. /**
  276. * 编辑事件
  277. */
  278. function handleEdit(record: Recordable) {
  279. if (isAdmin.value) {
  280. registerModal.value.disableSubmit = false;
  281. registerModal.value.edit(record);
  282. } else {
  283. return window.open(record.domain + '/adweb-admin/');
  284. }
  285. }
  286. /**
  287. * 详情
  288. */
  289. function handleDetail(record: Recordable) {
  290. registerModal.value.disableSubmit = true;
  291. registerModal.value.edit(record);
  292. }
  293. /**
  294. * 删除事件
  295. */
  296. async function handleDelete(record) {
  297. await deleteOne({ id: record.id }, handleSuccess);
  298. }
  299. async function siteDeleteStatus(record) {
  300. record.status = 0;
  301. await saveOrUpdate(record, true)
  302. .then((res) => {
  303. if (res.success) {
  304. createMessage.success(res.message);
  305. } else {
  306. createMessage.warning(res.message);
  307. }
  308. reload();
  309. })
  310. .finally(() => {});
  311. }
  312. function isSohoeb2bTenant() {
  313. getTenantById({ id: getAuthCache(TENANT_ID) }).then((res) => {
  314. isSohoeb2b.value = res.name.includes('苏豪纺织集团');
  315. });
  316. }
  317. /**
  318. * 批量删除事件
  319. */
  320. async function batchHandleDelete() {
  321. await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
  322. }
  323. /**
  324. * 成功回调
  325. */
  326. function handleSuccess() {
  327. (selectedRowKeys.value = []) && reload();
  328. }
  329. /**
  330. * 操作栏
  331. */
  332. function getTableAction(record) {
  333. return [
  334. {
  335. label: '编辑网站',
  336. onClick: handleEdit.bind(null, record),
  337. },
  338. ];
  339. }
  340. /**
  341. * 下拉操作栏
  342. */
  343. function getDropDownAction(record) {
  344. let dropDown = [
  345. // {
  346. // label: '详情',
  347. // onClick: handleDetail.bind(null, record),
  348. // },
  349. ];
  350. // 站点不是删除状态
  351. if (record.status === 2) {
  352. dropDown.push({
  353. label: '发布上线',
  354. onClick: wpSiteRelease.bind(null, record),
  355. });
  356. }
  357. // 针对苏豪纺织租户管理员,或者是管理员
  358. if ((isTenantAdmin.value && isSohoeb2b.value) || isAdmin.value) {
  359. dropDown.push({
  360. label: '订单设置',
  361. onClick: setSohoeb2bOrder.bind(null, record),
  362. });
  363. }
  364. dropDown.push({
  365. label: '询盘设置',
  366. onClick: setEnquiry.bind(null, record),
  367. });
  368. // 站点不是删除状态
  369. if (record.status != 0) {
  370. dropDown.push({
  371. label: '站点删除',
  372. onClick: siteDeleteStatus.bind(null, record),
  373. });
  374. }
  375. // 站点已发布,并且是正式域名时可以添加GTM 代码
  376. if (record.isDomain === 1 && record.status === 1) {
  377. dropDown.push(
  378. {
  379. label: 'GTM代码',
  380. onClick: addGtm.bind(null, record),
  381. },
  382. {
  383. label: 'Google Ads',
  384. onClick: bindGoogleAds.bind(null, record),
  385. }
  386. );
  387. }
  388. // 当前是管理员,并且站点是被删除状态
  389. if (isAdmin.value && record.status === 0) {
  390. dropDown.push({
  391. label: '资源删除',
  392. popConfirm: {
  393. title: '该站点将从系统中删除,站点资源将会保留15天,是否确认删除',
  394. confirm: handleDelete.bind(null, record),
  395. placement: 'topLeft',
  396. },
  397. });
  398. }
  399. return dropDown;
  400. }
  401. // 添加gtm
  402. function addGtm(r) {
  403. gtmRef.value.init(r);
  404. }
  405. // 询盘设置
  406. function setEnquiry(record) {
  407. siteSetEnquiryRef.value.init(record);
  408. }
  409. function setSohoeb2bOrder(record) {
  410. sohoeb2bOrderRef.value.init(record);
  411. }
  412. function wpSiteRelease(record) {
  413. siteReleaseRef.value.init(record);
  414. }
  415. /**
  416. * 查询
  417. */
  418. function searchQuery() {
  419. reload();
  420. }
  421. /**
  422. * 重置
  423. */
  424. function searchReset() {
  425. formRef.value.resetFields();
  426. if (queryParam.status) {
  427. delete queryParam.status;
  428. }
  429. if (queryParam.channelProviderId) {
  430. delete queryParam.channelProviderId;
  431. }
  432. selectedRowKeys.value = [];
  433. //刷新数据
  434. reload();
  435. }
  436. function handleProcess(record, type) {
  437. seoProcessVisible.value = true;
  438. processTitle.value = record.name;
  439. seoProcessRef.value.init(record, type);
  440. seoProcessRef.value.isCustomer = true;
  441. }
  442. function closeProcess() {
  443. seoProcessVisible.value = false;
  444. }
  445. function bindGoogleAds(record) {
  446. googleAdsModalRef.value.init({ record });
  447. }
  448. </script>
  449. <style lang="less" scoped>
  450. .jeecg-basic-table-form-container {
  451. padding: 0;
  452. .table-page-search-submitButtons {
  453. display: block;
  454. margin-bottom: 24px;
  455. white-space: nowrap;
  456. }
  457. .query-group-cust {
  458. min-width: 100px !important;
  459. }
  460. .query-group-split-cust {
  461. width: 30px;
  462. display: inline-block;
  463. text-align: center;
  464. }
  465. .ant-form-item:not(.ant-form-item-with-help) {
  466. margin-bottom: 16px;
  467. height: 32px;
  468. }
  469. :deep(.ant-picker),
  470. :deep(.ant-input-number) {
  471. width: 100%;
  472. }
  473. }
  474. </style>