<template>
  <a-card>
    <component
      :is="appId ? SdDataTableEx : SdDataTableSys"
      ref="autobhTable"
      ex
      form-id="oaAutonumber"
      :page-id="computedPageId"
      :columns="computedColumns"
      :show-selection="!appNodeId"
      :filter-expressions="expressions"
      :actions="appNodeId ? [] : actions"
      :search-fields="['businessTypeName']"
      :modal-props="{ footer: appNodeId ? null : undefined, class: $style.antobhModal }"
      @formBtnClick="formBtnClick"
    >
      <template v-slot:form="{ model }">
        <formWatcher
          :model="model"
          @formLoad="formLoad(model)"
          @change="fieleChange"
          @initData="initData"
        />
        <sd-form-item name="styleType" @change="styleTypeChange" />
        <div
          :class="[
            'form_sd-form_common',
            model.styleType === '1' ? $style.orderOne : $style.orderTwo,
          ]"
        >
          <sd-form-item name="numberType">
            <a-radio-group v-model="model.numberType">
              <a-radio value="1">
                流程
              </a-radio>
              <a-radio v-if="model.styleType === '0'" value="0">
                无流程
              </a-radio>
            </a-radio-group>
          </sd-form-item>
          <sd-form-item
            name="formRange"
            :input-props="{
              disabled: computedAppId && model.numberType === '0',
            }"
          />
          <sd-form-item name="formField">
            <template v-slot>
              <sd-tree-picker
                v-model="model.formField"
                :load-tree-data="computedAppId ? loadModuleTreePickerData : loadEntityFormTreeData"
              />
            </template>
            <template v-slot:read>
              <span>{{
                model.formField &&
                  typeof model.formField === 'string' &&
                  JSON.parse(model.formField)
                    .map((field) => field.name)
                    .join(',')
              }}</span>
            </template>
          </sd-form-item>
          <sd-form-item
            v-model="model.businessTypeRange"
            name="businessTypeRange"
            :input-props="{
              disabled: computedAppId && model.numberType === '1',
            }"
          />
          <sd-form-item name="businessField">
            <template v-slot>
              <sd-business-type-picker
                v-model="model.businessField"
                :single="model.styleType === '1'"
                :app-id="computedAppId"
                :belonged-org-id="computedAppId ? '' : belongedOrgId"
              />
            </template>
            <template v-slot:read>
              <span>{{
                model.businessField &&
                  typeof model.businessField === 'string' &&
                  JSON.parse(model.businessField)
                    .map((field) => field.name)
                    .join(',')
              }}</span>
            </template>
          </sd-form-item>
        </div>
        <div
          :class="[
            'form_sd-form_common',
            model.styleType === '1' ? $style.orderTwo : $style.orderOne,
          ]"
        >
          <sd-form-item
            v-if="computedAppId"
            name="appId"
            hidden
            :input-props="{ defaultValue: computedAppId }"
          />
          <sd-form-item name="recycleWay" />
          <a-form-item label="编号样式" required>
            <a-input-number
              v-if="model.styleType === '0'"
              v-model="inputNumberValue"
              :min="1"
              :class="[$style.inputnumbervalue, 'sd-shrinking-input']"
            />
            <span>
              <a-button
                size="small"
                :class="$style.numberstylebtn"
                @click="fnSetNumberStyle('LSH', 'num')"
                >位流水号</a-button
              >
              <a-button
                size="small"
                :class="$style.numberstylebtn"
                @click="fnSetNumberStyle('{YYYY}', 'date', 'YYYY')"
                >YYYY</a-button
              >
              <a-button
                size="small"
                :class="$style.numberstylebtn"
                @click="fnSetNumberStyle('{YY}', 'date', 'YY')"
                >YY</a-button
              >
              <a-button
                size="small"
                :class="$style.numberstylebtn"
                @click="fnSetNumberStyle('{MM}', 'date', 'MM')"
                >MM</a-button
              >
              <a-button
                size="small"
                :class="$style.numberstylebtn"
                @click="fnSetNumberStyle('{M}', 'date', 'M')"
                >M</a-button
              >
              <a-button
                size="small"
                :class="$style.numberstylebtn"
                @click="fnSetNumberStyle('{DD}', 'date', 'DD')"
                >DD</a-button
              >
              <a-button
                size="small"
                :class="$style.numberstylebtn"
                @click="fnSetNumberStyle('{D}', 'date', 'DD')"
                >D</a-button
              >
              <a-button
                size="small"
                :class="$style.numberstylebtn"
                @click="fnSetNumberStyle('{Dept}', 'Dept')"
                >部门</a-button
              >
            </span>

            <a-input
              v-if="model.styleType === '0'"
              v-model="model.numberStyle"
              placeholder="点击上方按钮可快速输入"
            />
            <sd-draggable
              v-if="model.styleType === '1' && numberStyle.length"
              v-model="numberStyle"
              handle=".drag-handle"
              :class="$style.draggable"
            >
              <a-row
                v-for="(item, index) in numberStyle"
                :key="index"
                :class="$style.dragRow"
                :gutter="8"
              >
                <a-col :span="1" class="drag-handle">⋮⋮</a-col>
                <a-col :span="6">
                  <a-select
                    v-model="item.id"
                    :options="numberStyleOptionss"
                    @change="() => (item.name = item.id === 'num' ? 1 : undefined)"
                  ></a-select>
                </a-col>
                <a-col :span="15">
                  <div :class="{ [$style.inlineSelect]: ['Dept', 'DeptCode'].includes(item.id) }">
                    <span v-if="['Dept', 'DeptCode'].includes(item.id)">组织展示级别</span>
                    <a-select
                      v-if="['Dept', 'DeptCode', 'date', 'var'].includes(item.id)"
                      v-model="item.name"
                      :options="getOptions(item)"
                      :placeholder="placeholderArr[item.id]"
                    />
                    <a-input-number
                      v-else-if="item.id === 'num'"
                      v-model="item.name"
                      placeholder="请输入位数"
                      :min="0"
                      :max="9"
                    />
                    <a-input v-else v-model="item.name" placeholder="请输入"></a-input>
                  </div>
                </a-col>
                <a-col :span="2">
                  <a-button
                    icon="delete"
                    :class="$style.add"
                    @click="delNumberStyle(item)"
                  ></a-button>
                </a-col>
              </a-row>
            </sd-draggable>
            <div>
              <a-button
                v-if="model.styleType === '1'"
                type="primary"
                icon="plus"
                :class="$style.add"
                @click="(e) => addNumberStyle()"
              />
            </div>
          </a-form-item>
          <sd-form-item name="numberRule">
            <template v-slot:read-and-edit="{ editable }">
              <a-radio-group v-model="model.numberRule" :disabled="!editable">
                <a-radio :value="0">
                  统一编号
                </a-radio>
                <a-radio :value="1">
                  按<a-select
                    v-model="model.numberField"
                    :class="$style.fieldSelect"
                    :options="getNumfieldOptions()"
                  />独自编号
                </a-radio>
              </a-radio-group>
            </template>
          </sd-form-item>

          <!-- 部门显示级别，样式中包含部门时显示 -->
          <sd-form-item
            name="orgLevelId"
            :hidden="
              !model.numberStyle ||
                model.numberStyle.indexOf('{Dept}') === -1 ||
                model.styleType === '1'
            "
          >
            <a-select v-model="model.orgLevelId" :options="DeptOptions" />
          </sd-form-item>
          <sd-form-item name="numberPreview">
            <template v-slot:read-and-edit>
              <a-row type="flex">
                <a-col :span="22">
                  {{ model.numberPreview }}
                </a-col>
                <a-col :span="2">
                  <a-button type="link" size="small" @click="preViewNumber">预览</a-button>
                </a-col>
              </a-row>
            </template>
          </sd-form-item>
          <sd-form-item
            v-if="model.numberStyle && model.numberStyle.indexOf('N}') > -1"
            name="initValue"
          >
            <a-input-number
              v-model="model.initValue"
              :min="1"
              :max="maxInitValue(model)"
            ></a-input-number>
          </sd-form-item>
          <sd-form-item name="reservedNumbers" />
          <sd-form-item name="currentNumber" />
        </div>
        <div :class="['form_sd-form_common', $style.status]">
          <sd-form-item name="status" />
        </div>
      </template>
    </component>
  </a-card>
</template>

<script>
import { sdLocalStorage } from '@/common/services/storage-service'
import asyncComponent from '@/common/services/async-component'
import axios from '@/common/services/axios-instance'
import TableColumnTypes from '@/common/services/table-column-types'
import ApplicationService from '@/application-manage/application-service'
import { message } from 'ant-design-vue'
import TableActionTypes from '../common/services/table-action-types'
import components from './_import-components/sd-autobh-list-import'

const columns = [
  {
    title: '循环方式',
    dataIndex: 'recycleWay',
  },
  {
    title: '编号样式',
    dataIndex: 'numberStyle',
    sdClickable: true,
  },
  {
    title: '当前字号',
    dataIndex: 'currentNumber',
  },
  {
    title: '使用业务类型',
    dataIndex: 'businessTypeName',
  },

  {
    title: '创建时间',
    dataIndex: 'creationTime',
    sdRender: TableColumnTypes.dateTime,
    sorter: true,
  },
  {
    title: '状态',
    dataIndex: 'status',
    sdRender: TableColumnTypes.ex.switch,
  },
]

export default {
  name: 'SdAutobhList',
  metaInfo: {
    title: '通用编号管理',
  },
  components: {
    ...components,
    formWatcher: {
      props: ['model'],
      created() {
        this.$emit('initData')
        this.$watch(
          () => this.model.numberType,
          () => this.$emit('formLoad'),
          { immediate: true }
        )
        this.$watch(
          () => this.model.businessField,
          () => this.$emit('change'),
          { immediate: true }
        )
      },
      render() {
        return ''
      },
    },
  },
  props: {
    appId: {
      type: String,
      default: '',
    },
    appNodeId: {
      type: String,
      default: undefined,
    },
  },
  data() {
    return {
      numberStyle: [],
      numberStyleOptionss: [
        { label: '日期', value: 'date' },
        { label: '流水号', value: 'num' },
        { label: '所属组织', value: 'Dept' },
        { label: '所属组织编码', value: 'DeptCode' },
        { label: '变量', value: 'var' },
        { label: '常量', value: 'const' },
      ],
      placeholderArr: {
        Dept: '请选择组织显示级别',
        DeptCode: '请选择组织编码显示级别',
        var: '请选择字段',
        date: '请选择日期格式',
      },
      dateOptions: ['YYYY', 'YY', 'MM', 'M', 'DD', 'D'].map((item) => ({
        label: item,
        value: item,
      })),
      DeptCodeOptions: [],
      DeptOptions: [],
      varOptions: [],
      inputNumberValue: 1,
      columns,
      actions: [
        {
          label: '新建',
          id: 'new',
          type: TableActionTypes.primary,
          permission: 'create',
          callback: this.fnCreate,
        },
        {
          label: '删除',
          id: 'delete',
          type: TableActionTypes.ex.delete,
        },
      ],
      routeAppId: null,
    }
  },
  computed: {
    computedAppId() {
      return this.appId || this.routeAppId
    },
    expressions() {
      const expressions = [
        {
          dataType: 'str',
          name: 'appId',
          op: this.computedAppId ? 'eq' : 'is_null',
          stringValue: this.computedAppId,
        },
      ]
      return expressions
    },
    belongedOrgId() {
      const belongedOrg = this.$refs.autobhTable?.getHierarchy()
      return belongedOrg?.id || ''
    },
    computedColumns() {
      if (this.appNodeId) {
        return this.columns.filter((col) => col.dataIndex !== 'status')
      }
      return this.columns
    },
    computedPageId() {
      if (this.appNodeId) {
        return 'base/autonumber/oaAutonumber?mode=VIEW'
      }
      return 'base/autonumber/oaAutonumber'
    },
  },
  created() {
    this.SdDataTableEx = asyncComponent(() =>
      import(/* webpackChunkName: "sd-data-table" */ '@/common/components/sd-data-table-ex.vue')
    )
    this.SdDataTableSys = asyncComponent(() =>
      import(/* webpackChunkName: "sd-data-table" */ '@/common/components/sd-data-table-sys.vue')
    )
    this.routeAppId = this.$route.query.appId
    axios.get('api/framework/v1/level/group-levels').then((res) => {
      this.DeptCodeOptions = this.DeptOptions = res.data.map((item) => ({
        value: item.id,
        label: item.name,
      }))
    })
  },
  methods: {
    styleTypeChange() {
      const styleType = this.$refs.autobhTable.getDetailModal().getFieldValue('styleType')
      this.$refs.autobhTable.getDetailModal().setFieldsValue({
        formRange: null,
        businessTypeRange: null,
        businessField: null,
        numberStyle: null,
        numberPreview: null,
        numberType: styleType === '1' ? '1' : null,
        currentNumber: null,
      })
      this.numberStyle = []
    },
    initData() {
      this.$nextTick(() => {
        const numberStyleDisplay = this.$refs.autobhTable
          .getDetailModal()
          .getFieldValue('numberStyleDisplay')
        this.numberStyle = JSON.parse(numberStyleDisplay || '[]')
      })
    },
    formBtnClick(evt, btn, { form, recordId }) {
      if (btn.buttonId === 'save') {
        evt.waitUntil(
          new Promise((resolve, reject) => {
            if (form.getFieldValue('styleType') === '1') {
              const numberRule = form.getFieldValue('numberRule')
              const numberField = form.getFieldValue('numberField')
              if (numberRule && !numberField) {
                message.warn('请检查编号规则填写！')
                reject(new Error())
              }
              this.setNumberStyle()
              const deptStyle =
                this.numberStyle.find((f) => ['Dept', 'DeptCode'].includes(f.id))?.name || ''
              form.setFieldsValue({
                numberStyleDisplay: JSON.stringify(this.numberStyle),
                orgLevelId: deptStyle,
              })
              resolve()
            } else resolve()
          })
        )
      }
    },
    setNumberStyle() {
      if (this.numberStyle.length) {
        const numberStyle = this.numberStyle
          .filter((f) => f.id && f.name)
          .map((m) => {
            let styleValue = ''
            switch (m.id) {
              case 'const':
                styleValue = m.name
                break
              case 'num':
                styleValue = '{'
                for (var i = 0; i < m.name; i++) {
                  styleValue = styleValue + 'N'
                }
                styleValue = styleValue + '}'
                break
              case 'Dept':
                styleValue = '{' + m.id + '}'
                break
              case 'DeptCode':
                styleValue = '{' + m.id + '}'
                break
              default:
                styleValue = '{' + m.name + '}'
            }
            return styleValue
          })
        this.$refs.autobhTable.getDetailModal().setFieldValue('numberStyle', numberStyle.join(''))
      }
    },
    fieleChange() {
      this.$nextTick(() => {
        const businessField = this.$refs.autobhTable.getDetailModal().getFieldValue('businessField')
        const styleType = this.$refs.autobhTable.getDetailModal().getFieldValue('styleType')
        if (businessField && styleType === '1') {
          const businessFieldValue = Array.isArray(businessField)
            ? businessField
            : JSON.parse(businessField)
          axios
            .get(
              `api/framework/v1/autonumber-manager/fields?businessTypeId=${businessFieldValue[0].id}`
            )
            .then((res) => {
              this.varOptions = res.data.map((item) => ({
                label: item.value,
                value: item.name,
                type: item.type,
              }))
            })
        }
      })
    },
    getOptions(item) {
      return this[`${item.id}Options`]
    },
    getNumfieldOptions() {
      let options = []
      if (this.numberStyle.find((style) => style.id === 'Dept' && style.name)) {
        options.push({ label: '所属组织', value: 'Dept' })
      }
      if (this.numberStyle.find((style) => style.id === 'DeptCode' && style.name)) {
        options.push({ label: '所属组织编码', value: 'DeptCode' })
      }
      if (this.numberStyle.find((style) => style.id === 'var' && style.name)) {
        const varStyles = this.numberStyle.filter((style) => style.id === 'var').map((m) => m.name)
        const varOptions = this.varOptions.filter(
          (option) => varStyles.includes(option.value) && option.type === 'selectlist'
        )
        options = [...options, ...varOptions]
      }
      return options
    },
    addNumberStyle(id = undefined, name = undefined) {
      this.numberStyle.push({ id, name, key: new Date().valueOf() })
    },
    delNumberStyle(record) {
      this.numberStyle = this.numberStyle.filter((s) => s.key !== record.key)
    },
    loadEntityFormTreeData(parentCatId = 'V-3') {
      const groupId =
        JSON.parse(sdLocalStorage.getItem('hierarchicalInfo') || '{}')?.authGroupId || ''
      const cateParams = {
        groupId,
        parentCatId: parentCatId,
        isPage: false,
      }
      const leafParams = {
        groupId,
        parentCatId: parentCatId,
        isPage: true,
      }
      // 获取分类+页面
      return Promise.all([
        ApplicationService.getEntityFormData(cateParams),
        ApplicationService.getEntityFormData(leafParams),
      ]).then((items) => {
        return (items[0] || [])
          .map((item) => ({
            id: item.props?.formId || item.id,
            name: item.text,
            checkable: false,
            isLeaf: item.leaf,
          }))
          .concat(
            (items[1] || []).map((item) => ({
              id: item.props?.formId || item.id,
              name: item.text,
              checkable: true,
              isLeaf: item.leaf,
              props: item.props,
            }))
          )
      })
    },
    loadModuleTreePickerData(parentCatId) {
      const params = { appId: this.computedAppId }
      if (parentCatId) {
        // 非根节点
        params.parentId = parentCatId
      }
      return ApplicationService.getModuleTree(params).then((res) => {
        const allModules = res.data
          .map((d) => {
            return {
              id: d.props?.formId,
              name: d.text,
              checkable: d.props?.isChoice === 'true',
              isLeaf: d.leaf,
              props: d.props,
            }
          })
          .filter((f) => f.props?.isFlow === '0')
        return allModules
      })
    },
    formLoad(model) {
      // 根据编号样式（流水号个数）设置位数
      this.inputNumberValue = model.numberStyle?.match(/\{(?<lsh>N+)\}/)?.groups?.lsh?.length || 1
      this.$nextTick(() => {
        if (model.styleType === '0') {
          this.$refs.autobhTable.getDetailModal().setFieldsValue({
            formRange: model.numberType === '0' && this.computedAppId ? 'range' : model.formRange,
            businessTypeRange:
              model.numberType === '1' && this.computedAppId ? 'range' : model.businessTypeRange,
          })
        }
      })
    },
    maxInitValue(model) {
      const nStyle = model.numberStyle.match(/\{(.+?)\}/g).find((item) => item.indexOf('N') > -1)
      return Math.pow(10, nStyle.length - 2) - 1
    },
    // 新建
    fnCreate() {
      this.$refs.autobhTable.showDetailModal()
    },
    fnSetNumberStyle(item, type, cusValue) {
      const styleType = this.$refs.autobhTable.getDetailModal().getFieldValue('styleType')
      if (styleType === '0') {
        let clickValue = item
        let value = this.$refs.autobhTable.getDetailModal().getFieldValue('numberStyle')
        if (item === 'LSH') {
          var strStyle = '{'
          for (var i = 0; i < this.inputNumberValue; i++) {
            strStyle = strStyle + 'N'
          }
          strStyle = strStyle + '}'
          clickValue = strStyle
        }
        const nStr = value?.match(/\{(.+?)\}/g)?.find((item) => item.indexOf('N') > -1)
        if (nStr && item === 'LSH') {
          value = value.replace(nStr, clickValue)
        } else {
          value = value ? value + clickValue : clickValue
        }
        this.$refs.autobhTable.getDetailModal().setFieldValue('numberStyle', value)
        this.$refs.autobhTable.getDetailModal().validateField('numberStyle')
      } else this.addNumberStyle(type, cusValue)
    },
    preViewNumber() {
      this.setNumberStyle()
      const detailForm = this.$refs.autobhTable.getDetailModal()
      detailForm.validateField('numberStyle').then((flag) => {
        if (flag) {
          const data = {
            numberStyle: detailForm.getFieldValue('numberStyle'),
            currentSerial: detailForm.getFieldValue('currentSerial'),
            initValue: detailForm.getFieldValue('initValue'),
            orgLevelId: detailForm.getFieldValue('orgLevelId'),
          }
          axios({
            url: 'api/framework/v1/autonumber-manager/get-number-preview',
            method: 'post',
            data,
          }).then((res) => {
            detailForm.setFieldValue('numberPreview', res.data.toString())
          })
        }
      })
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
$inputnumbervalue: 8px;
.inputnumbervalue {
  margin-right: $inputnumbervalue;
}
.numberstylebtn {
  margin-right: $inputnumbervalue;
  background-color: $btn-disable-bg;
}
.antobh-modal {
  :global .ant-form {
    display: grid;
  }
  .order-one {
    order: 1;
  }
  .order-two {
    order: 2;
  }
  .status {
    order: 3;
  }
}
.draggable:not(.sd-dragging) {
  .drag-row {
    :global .drag-handle {
      /* stylelint-disable-next-line */
      color: #999;
    }
  }
}
.inline-select {
  :global .ant-select {
    display: inline-block;
    max-width: 71%;
    margin-left: 1%;
  }
}
.field-select {
  margin: 0 5px;
}
</style>
