广丰卷烟厂数采质量分析系统
zhuguifei
7 天以前 2b31fa203f3435a582be51f45899d99164c9917a
ruoyi-plus-soybean/src/views/qm/std/modules/std-sub-table.vue
old mode 100644 new mode 100755
@@ -1,9 +1,14 @@
<script setup lang="tsx">
import { computed, ref, watch } from 'vue';
import { useLoading } from '@sa/hooks';
import { $t } from '@/locales';
import { fetchGetCheckitemTree } from '@/service/api/qm/checkitem';
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import type { DataTableColumns, DataTableRowKey } from 'naive-ui';
import { NDivider } from 'naive-ui';
import { useLoading } from '@sa/hooks';
import { jsonClone } from '@sa/utils';
import { fetchBatchDeleteCheckitem, fetchGetCheckitemTree } from '@/service/api/qm/checkitem';
import { useAuth } from '@/hooks/business/auth';
import { $t } from '@/locales';
import ButtonIcon from '@/components/custom/button-icon.vue';
import CheckitemOperateDrawer from '@/views/qm/checkitem/modules/checkitem-operate-drawer.vue';
defineOptions({
  name: 'StdSubTable'
@@ -11,10 +16,12 @@
interface Props {
  stdId?: CommonType.IdType | null;
  stdCode?: string | '';
}
const props = withDefaults(defineProps<Props>(), {
  stdId: null
  stdId: null,
  stdCode: ''
});
interface StdSubRow extends Api.Qm.Checkitem {
@@ -22,10 +29,24 @@
}
const { loading, startLoading, endLoading } = useLoading();
const { hasAuth } = useAuth();
const rows = ref<StdSubRow[]>([]);
const checkedRowKeys = ref<CommonType.IdType[]>([]);
const drawerVisible = ref(false);
const operateType = ref<NaiveUI.TableOperateType>('add');
const editingData = ref<Api.Qm.Checkitem | null>(null);
const showFullscreen = ref(false);
const fullscreenStyle = ref<Record<string, string>>({});
const onFullscreenKeydown = (event: KeyboardEvent) => {
  if (event.key === 'Escape') {
    showFullscreen.value = false;
  }
};
const cardTitle = computed(() => `规程明细${props.stdCode || ''}`);
async function getSubList() {
  if (!props.stdId) {
  if (!props.stdId && !props.stdCode) {
    rows.value = [];
    return;
  }
@@ -35,7 +56,7 @@
    const { data, error } = await fetchGetCheckitemTree({
      pageNum: 1,
      pageSize: 9999,
      stdCode: String(props.stdId)
      stdCode: props.stdId != null ? String(props.stdId) : String(props.stdCode)
    });
    if (error) {
      rows.value = [];
@@ -49,14 +70,100 @@
}
watch(
  () => props.stdId,
  () => [props.stdId, props.stdCode],
  async () => {
    checkedRowKeys.value = [];
    await getSubList();
  },
  { immediate: true }
);
watch(
  showFullscreen,
  visible => {
    if (visible) {
      updateFullscreenStyle();
      window.addEventListener('keydown', onFullscreenKeydown);
      window.addEventListener('resize', updateFullscreenStyle);
      window.addEventListener('scroll', updateFullscreenStyle, true);
      return;
    }
    window.removeEventListener('keydown', onFullscreenKeydown);
    window.removeEventListener('resize', updateFullscreenStyle);
    window.removeEventListener('scroll', updateFullscreenStyle, true);
  },
  { immediate: true }
);
onBeforeUnmount(() => {
  window.removeEventListener('keydown', onFullscreenKeydown);
  window.removeEventListener('resize', updateFullscreenStyle);
  window.removeEventListener('scroll', updateFullscreenStyle, true);
});
onMounted(() => {
  updateFullscreenStyle();
});
function updateFullscreenStyle() {
  const container = document.querySelector<HTMLElement>('.std-content-area');
  if (!container) {
    fullscreenStyle.value = {
      position: 'fixed',
      inset: '0',
      zIndex: '20'
    };
    return;
  }
  const rect = container.getBoundingClientRect();
  fullscreenStyle.value = {
    position: 'fixed',
    left: `${rect.left}px`,
    top: `${rect.top}px`,
    width: `${rect.width}px`,
    height: `${rect.height}px`,
    zIndex: '20'
  };
}
function handleAdd() {
  if (!props.stdId && !props.stdCode) {
    window.$message?.warning('请先选择规程');
    return;
  }
  operateType.value = 'add';
  editingData.value = null;
  drawerVisible.value = true;
}
function handleEdit(row: StdSubRow) {
  operateType.value = 'edit';
  editingData.value = jsonClone(row);
  drawerVisible.value = true;
}
async function handleBatchDelete() {
  if (checkedRowKeys.value.length === 0) return;
  const { error } = await fetchBatchDeleteCheckitem(checkedRowKeys.value);
  if (error) return;
  window.$message?.success($t('common.deleteSuccess'));
  checkedRowKeys.value = [];
  await getSubList();
}
async function handleDelete(id: CommonType.IdType) {
  const { error } = await fetchBatchDeleteCheckitem([id]);
  if (error) return;
  window.$message?.success($t('common.deleteSuccess'));
  await getSubList();
}
const columns = computed<DataTableColumns<StdSubRow>>(() => [
  {
    type: 'selection',
    align: 'center',
    width: 48
  },
  {
    key: 'index',
    title: $t('common.index'),
@@ -101,6 +208,59 @@
    title: '描述',
    align: 'center',
    minWidth: 160
  },
  {
    key: 'operate',
    title: $t('common.operate'),
    align: 'center',
    width: 130,
    render: row => {
      const divider = () => {
        if (!hasAuth('qm:checkitem:edit') || !hasAuth('qm:checkitem:remove')) {
          return null;
        }
        return <NDivider vertical />;
      };
      const editBtn = () => {
        if (!hasAuth('qm:checkitem:edit')) {
          return null;
        }
        return (
          <ButtonIcon
            text
            type="primary"
            icon="material-symbols:drive-file-rename-outline-outline"
            tooltipContent={$t('common.edit')}
            onClick={() => handleEdit(row)}
          />
        );
      };
      const deleteBtn = () => {
        if (!hasAuth('qm:checkitem:remove')) {
          return null;
        }
        return (
          <ButtonIcon
            text
            type="error"
            icon="material-symbols:delete-outline"
            tooltipContent={$t('common.delete')}
            popconfirmContent={$t('common.confirmDelete')}
            onPositiveClick={() => handleDelete(row.id)}
          />
        );
      };
      return (
        <div class="flex-center gap-8px">
          {editBtn()}
          {divider()}
          {deleteBtn()}
        </div>
      );
    }
  }
]);
@@ -111,20 +271,38 @@
<template>
  <NCard
    title="规程明细"
    :title="cardTitle"
    :bordered="false"
    size="small"
    class="flex-col-stretch card-wrapper"
    :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
  >
    <template #header-extra>
      <span class="text-13px text-gray-500">{{ props.stdId ? `STD CODE:${props.stdId}` : '' }}</span>
      <NSpace align="center">
        <TableHeaderOperation
          :disabled-delete="checkedRowKeys.length === 0"
          :loading="loading"
          :show-add="hasAuth('qm:checkitem:add')"
          :show-delete="hasAuth('qm:checkitem:remove')"
          :show-export="false"
          @add="handleAdd"
          @delete="handleBatchDelete"
          @refresh="getSubList"
        />
        <NButton size="small" @click="showFullscreen = true">
          <template #icon>
            <icon-mdi-fullscreen class="text-icon" />
          </template>
          全屏
        </NButton>
      </NSpace>
    </template>
    <NSpin :show="loading" class="h-full" content-class="h-full">
      <div v-if="!props.stdId" class="h-full flex-center text-gray-400">请点击上方表格行查看明细</div>
      <div v-if="!props.stdId && !props.stdCode" class="h-full flex-center text-gray-400">请点击上方表格行查看明细</div>
      <NDataTable
        v-else
        v-model:checked-row-keys="checkedRowKeys"
        :columns="columns as any"
        :data="rows"
        size="small"
@@ -137,6 +315,65 @@
      />
    </NSpin>
  </NCard>
  <Teleport to="body">
    <div v-if="showFullscreen" class="fullscreen-mask" :style="fullscreenStyle" @click.self="showFullscreen = false">
      <NCard
        :title="cardTitle"
        :bordered="false"
        size="small"
        class="fullscreen-card flex-col-stretch"
        :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
      >
        <template #header-extra>
          <NSpace align="center">
            <TableHeaderOperation
              :disabled-delete="checkedRowKeys.length === 0"
              :loading="loading"
              :show-add="hasAuth('qm:checkitem:add')"
              :show-delete="hasAuth('qm:checkitem:remove')"
              :show-export="false"
              @add="handleAdd"
              @delete="handleBatchDelete"
              @refresh="getSubList"
            />
            <NButton size="small" ghost type="error" @click="showFullscreen = false">
              <template #icon>
                <icon-mdi-close class="text-icon" />
              </template>
              关闭
            </NButton>
          </NSpace>
        </template>
        <NSpin :show="loading" class="h-full" content-class="h-full">
          <div v-if="!props.stdId && !props.stdCode" class="h-full flex-center text-gray-400">
            请点击上方表格行查看明细
          </div>
          <NDataTable
            v-else
            v-model:checked-row-keys="checkedRowKeys"
            :columns="columns as any"
            :data="rows"
            size="small"
            flex-height
            children-key="children"
            :row-key="rowKey"
            striped
            class="fullscreen-table"
          />
        </NSpin>
      </NCard>
    </div>
  </Teleport>
  <CheckitemOperateDrawer
    v-model:visible="drawerVisible"
    :operate-type="operateType"
    :row-data="editingData"
    :std-code="props.stdId"
    @submitted="getSubList"
  />
</template>
<style scoped>
@@ -148,4 +385,22 @@
:deep(.n-data-table-td) {
  padding: 4px 6px;
}
.fullscreen-mask {
  position: absolute;
  inset: 0;
  z-index: 20;
  background: #fff;
  padding: 0;
  display: flex;
}
.fullscreen-card {
  width: 100%;
  height: 100%;
}
.fullscreen-table {
  height: 100%;
}
</style>