index.vue 10.5 KB
<script setup lang="ts">
  import { computed, createVNode, onMounted, ref } from 'vue';
  import useLoading from '@/hooks/loading';
  import { AnyObject, AttributeData, QueryForParams } from '@/types/global';
  import { useRoute, useRouter } from 'vue-router';
  import { isArray } from '@/utils/is';
  import usePermission from '@/hooks/permission';
  import useActivityApi, { useApplyApi } from '@/http/activity';
  import NumberTableColumn from '@/components/filter/number-table-column.vue';
  import ActivityTableColumn from '@/components/filter/activity-table-column.vue';
  import DateTableColumn from '@/components/filter/date-table-column.vue';
  import EnumTableColumn from '@/components/filter/enum-table-column.vue';
  import SpaceTableColumn from '@/components/filter/space-table-column.vue';
  import ActivityForm from '@/views/audition/demo-apply/components/form-content.vue';
  import { Message, TableData } from '@arco-design/web-vue';
  import { createInputVNode, createModalVNode } from '@/utils/createVNode';
  import { promiseToBoolean } from '@/utils';
  import openNewTab from '@/utils/route-blank';
  import { useSelectionStore } from '@/store';
  import { Project } from '@/utils/model';
  import { tryOnMounted } from '@vueuse/core';
  import { split } from 'lodash';

  const router = useRouter();

  const checkPermission = (permission: string | string[]): boolean => {
    let routeName = useRoute().name as string;
    routeName = routeName === 'audition-demo' ? routeName : `${routeName}-demo`;
    permission = isArray(permission) ? permission.map((item) => `${routeName}-${item}`) : `${routeName}-${permission}`;
    return usePermission().checkPermission(permission);
  };
  const hasPermission = computed(() => checkPermission(['show', 'status', 'edit']));

  const { statusOption, get, getExport, update, changeStatus } = useActivityApi;

  const platformOption = [
    { label: '厂牌Demo', value: '0,1' },
    { label: '个人Demo', value: '2' },
  ];

  const tableRef = ref();
  const { loading, setLoading } = useLoading(false);
  const filter = ref<QueryForParams>({});

  const props = withDefaults(
    defineProps<{
      initFilter?: AttributeData;
      hideSearchItem?: string[];
      hideColumnItem?: string[];
      exportName?: string;
      createProp?: object;
      queryHook?: () => void;
    }>(),
    {
      hideSearchItem: ['createBetween'] as any,
    }
  );

  const onQuery = async (params?: AnyObject) => {
    setLoading(true);
    props.queryHook?.();
    return get({
      ...filter.value,
      ...params,
      createdForm: filter.value.createdForm ? split(filter.value.createdForm as string, ',') : [],
      setColumn: [
        'id',
        'song_name',
        'cover',
        'lang',
        'speed',
        'sub_title',
        'sex',
        'user_id',
        'project_id',
        'send_url',
        'match_day',
        'send_url',
        'lyric',
        'clip_lyric',
        'is_push',
        'is_official',
        'mark',
        'expand',
        'weight',
        'status',
        'estimate_release_at',
        'audit_at',
        'created_at',
        'created_form',
        'match_at',
        'match_day',
      ],
      setWith: [
        'project:id,name',
        'user:id,real_name,nick_name,identity',
        'tags:id,name',
        'outSideManages:id,user_id,activity_id,permission',
      ],
      setWithCount: ['viewUsers as view_count', 'collectionUsers as like_count'],
    }).finally(() => setLoading(false));
  };

  const onSort = (column: string, type: string) => {
    filter.value.setSort = type ? [(type === 'desc' ? '-' : '') + column, '-id'] : ['-audit_at', '-id'];
    tableRef.value?.onFetch();
  };

  const onSearch = () => tableRef.value?.onPageChange(1);

  const onReset = () => {
    filter.value = {
      songName: '',
      projectName: '',
      tagName: '',
      userName: '',
      createdForm: '',
      status: [],
      createBetween: [],
      ...props.initFilter,
      songType: 2,
      setSort: ['-audit_at'],
    };
    tableRef.value?.resetSort();
    onSearch();
  };

  onMounted(() => onReset());
  tryOnMounted(async () => useSelectionStore().queryAll());

  const onExport = () =>
    getExport(props.exportName || 'Demo', {
      ...filter.value,
      createdForm: filter.value.createdForm ? split(filter.value.createdForm as string, ',') : [],
    });
  const onShow = (record: TableData) => openNewTab(router, 'audition-demo-show', { id: record.id });

  const onDown = (record: TableData) => {
    const msg = ref<string>('');

    createModalVNode(() => createInputVNode(msg, { 'placeholder': '请输入下架原因', 'maxLength': 20, 'show-word-limit': true }), {
      title: '变更状态',
      titleAlign: 'start',
      okText: '下架',
      onBeforeOk: () => promiseToBoolean(changeStatus(record.id, { status: 'down', msg: msg.value })),
      onOk: () => tableRef.value?.onFetch(),
    });
  };

  const onUp = (record: TableData, status: 'up' | 'reUp') => {
    createModalVNode(`请确认是否上架Demo:${record.song_name}`, {
      title: '变更状态',
      titleAlign: 'start',
      okText: '上架',
      onBeforeOk: () => promiseToBoolean(changeStatus(record.id, { status })),
      onOk: () => tableRef.value?.onFetch(),
    });
  };
  const onCreate = () => {
    const dialog = createModalVNode(
      () =>
        createVNode(ActivityForm, {
          initValue: { song_type: 2, cover: useSelectionStore().appleDemoCover, created_form: 1, is_push: 0, expand: { push_type: [] } },
          filterProject: (value: Project) => value.is_can_demo_apply === 1,
          onSubmit: (data: AnyObject) =>
            useApplyApi.create(data).then(() => {
              Message.success(`申请上架Demo:${data.song_name}`);
              tableRef.value?.onFetch();
              dialog.close();
            }),
        }),
      { title: '创建Demo', footer: false, closable: true, width: 'auto' }
    );
  };

  const onUpdate = (record: TableData) => {
    const dialog = createModalVNode(
      () =>
        createVNode(ActivityForm, {
          initValue: record,
          filterProject: (value: Project) => value.is_can_demo_apply === 1 || value.id === record.project_id,
          onSubmit: (attribute: AnyObject) =>
            update(record.id, Object.assign(attribute, { song_type: 2 })).then(() => {
              Message.success(`编辑Demo:${record.song_name}`);
              tableRef.value?.onFetch();
              dialog.close();
            }),
        }),
      { title: '编辑Demo', footer: false, width: 'auto', closable: true }
    );
  };

  const onDelete = (row: TableData) =>
    createModalVNode(`确认要将Demo:${row.song_name} 删除吗?`, {
      title: '删除操作',
      onBeforeOk: () => promiseToBoolean(useActivityApi.destroy(row.id)),
      onOk: () => tableRef.value?.onFetch(),
    });
</script>

<template>
  <page-view has-bread has-card>
    <filter-search :model="filter" :loading="loading" @search="onSearch" @reset="onReset">
      <filter-search-item label="歌曲名称" field="song_name">
        <a-input v-model="filter.songName" allow-clear placeholder="请输入" />
      </filter-search-item>
      <filter-search-item v-if="!hideSearchItem?.includes('projectName')" label="厂牌名称" field="projectName">
        <a-input v-model="filter.projectName" allow-clear placeholder="请输入" />
      </filter-search-item>
      <filter-search-item v-if="!hideSearchItem?.includes('userName')" label="用户名称" field="userName">
        <a-input v-model="filter.userName" allow-clear placeholder="请输入" />
      </filter-search-item>
      <filter-search-item v-if="!hideSearchItem?.includes('createdForm')" label="关联类别" field="createdForm">
        <a-select v-model="filter.createdForm" :options="platformOption" allow-clear placeholder="请选择" />
      </filter-search-item>
      <filter-search-item label="标签名称" field="tagName">
        <a-input v-model="filter.tagName" allow-clear placeholder="请输入" />
      </filter-search-item>
      <filter-search-item label="状态" field="status">
        <a-select v-model="filter.status" :options="statusOption" allow-clear multiple placeholder="请选择" />
      </filter-search-item>
      <filter-search-item v-if="!hideSearchItem?.includes('createBetween')" label="创建时间" field="createBetween">
        <a-range-picker v-model="filter.createBetween" show-time :time-picker-props="{ defaultValue: ['00:00:00', '23:59:59'] }" />
      </filter-search-item>
    </filter-search>
    <filter-table ref="tableRef" :loading="loading" :on-query="onQuery" @row-sort="onSort">
      <template #tool>
        <icon-button v-if="checkPermission('create')" icon="plus" label="新增" type="primary" @click="onCreate" />
      </template>
      <template #tool-right>
        <export-button v-if="checkPermission('export')" :on-download="onExport" />
      </template>
      <activity-table-column data-index="id" title="试唱歌曲" :width="420" hide-sub-title />
      <number-table-column data-index="view_count" title="试听人数" :dark-value="0" :width="110" has-sort />
      <number-table-column data-index="like_count" title="收藏人数" :dark-value="0" :width="110" has-sort />
      <date-table-column data-index="created_at" title="创建时间" :width="100" split has-sort />
      <enum-table-column data-index="status" title="状态" :option="statusOption" :width="80" has-sort />
      <space-table-column v-if="hasPermission" :width="80" data-index="operations" fixed="right" title="操作" direction="vertical">
        <template #default="{ record }">
          <a-link v-if="checkPermission('show')" class="link-hover" :hoverable="false" @click="onShow(record)"> 查看 </a-link>
          <a-link
            v-if="record.status !== 0 && record.status !== 5 && checkPermission('edit')"
            class="link-hover"
            :hoverable="false"
            @click="onUpdate(record)"
          >
            编辑
          </a-link>
          <a-link v-if="record.status === 1 && checkPermission('status')" class="link-hover" :hoverable="false" @click="onDown(record)">
            下架
          </a-link>
          <a-link v-if="record.status === 2 && checkPermission('status')" class="link-hover" :hoverable="false" @click="onUp(record, 'up')">
            上架
          </a-link>
          <a-link v-if="record.status === 2 && checkPermission('delete')" class="link-hover" :hoverable="false" @click="onDelete(record)">
            删除
          </a-link>
        </template>
      </space-table-column>
    </filter-table>
  </page-view>
</template>

<style scoped lang="less"></style>