<template>
  <div class="container role-list" v-loading="loading">
    <div class="handle-box">
      <el-button type="primary" :icon="Plus" @click="addRole">新增</el-button>
    </div>
    <el-row>
      <el-table :data="tableData" :border="parentBorder" style="width: 100%">
        <el-table-column type="expand">
          <template #default="props">
            <div>
              <el-table :data="props.row.context" :border="childBorder">
                <el-table-column label="对话应用" prop="role" width="120"/>
                <el-table-column label="对话内容" prop="content"/>
              </el-table>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="应用名称" prop="name">
          <template #default="scope">
            <span class="sort" :data-id="scope.row.id">{{ scope.row.name }}</span>
          </template>
        </el-table-column>
        <el-table-column label="应用标识" prop="key"/>
        <el-table-column label="绑定模型" prop="model_name"/>
        <el-table-column label="启用状态">
          <template #default="scope">
            <el-switch v-model="scope.row['enable']" @change="roleSet('enable',scope.row)"/>
          </template>
        </el-table-column>
        <el-table-column label="应用图标" prop="icon">
          <template #default="scope">
            <el-image :src="scope.row.icon" style="width: 45px; height: 45px; border-radius: 50%"/>
          </template>
        </el-table-column>
        <el-table-column label="打招呼信息" prop="hello_msg"/>
        <el-table-column label="操作" width="150" align="right">
          <template #default="scope">
            <el-button size="small" type="primary" @click="rowEdit(scope.$index, scope.row)">编辑</el-button>
            <el-popconfirm title="确定要删除当前应用吗?" @confirm="removeRole(scope.row)" :width="200">
              <template #reference>
                <el-button size="small" type="danger">删除</el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
    </el-row>

    <el-dialog
        v-model="showDialog"
        :title="optTitle"
        :close-on-click-modal="false"
        width="50%"
    >
      <el-form :model="role" label-width="120px" ref="formRef" label-position="left" :rules="rules">
        <el-form-item label="应用名称：" prop="name">
          <el-input
              v-model="role.name"
              autocomplete="off"
          />
        </el-form-item>

        <el-form-item label="应用标志：" prop="key">
          <el-input
              v-model="role.key"
              autocomplete="off"
          />
        </el-form-item>

        <el-form-item label="应用图标：" prop="icon">
          <el-input v-model="role.icon">
            <template #append>
              <el-upload
                  :auto-upload="true"
                  :show-file-list="false"
                  :http-request="uploadImg"
              >
                上传
              </el-upload>
            </template>
          </el-input>
        </el-form-item>

        <el-form-item label="绑定模型：" prop="model_id">
          <el-select
              v-model="role.model_id"
              filterable
              placeholder="请选择模型"
              clearable
          >
            <el-option
                v-for="item in models"
                :key="item.id"
                :label="item.name"
                :value="item.id"
            />
          </el-select>
        </el-form-item>

        <el-form-item label="打招呼信息：" prop="hello_msg">
          <el-input
              v-model="role.hello_msg"
              autocomplete="off"
          />
        </el-form-item>

        <el-form-item label="上下文信息：" prop="context">
          <template #default>
            <el-table :data="role.context" :border="childBorder" size="small">
              <el-table-column label="对话应用" width="120">
                <template #default="scope">
                  <el-input
                      v-model="scope.row.role"
                      autocomplete="off"
                  />
                </template>
              </el-table-column>
              <el-table-column label="对话内容">
                <template #header>
                  <div class="context-msg-key">
                    <span>对话内容</span>
                    <span class="fr">
                      <el-button type="primary" @click="addContext" size="small">
                      <el-icon>
                        <Plus/>
                      </el-icon>
                      增加一行
                    </el-button>
                    </span>
                  </div>
                </template>

                <template #default="scope">
                  <div class="context-msg-content">
                    <el-input
                        type="textarea"
                        :rows="2"
                        v-model="scope.row.content"
                        autocomplete="off"
                    />
                    <span><el-icon @click="removeContext(scope.$index)"><RemoveFilled/></el-icon></span>
                  </div>
                </template>
              </el-table-column>
            </el-table>
          </template>
        </el-form-item>

        <el-form-item label="启用状态">
          <el-switch v-model="role.enable"/>
        </el-form-item>
      </el-form>

      <template #footer>
            <span class="dialog-footer">
              <el-button @click="showDialog = false">取消</el-button>
              <el-button type="primary" @click="save">保存</el-button>
            </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>

import {Plus, RemoveFilled} from "@element-plus/icons-vue";
import {onMounted, reactive, ref} from "vue";
import {httpGet, httpPost} from "@/utils/http";
import {ElMessage} from "element-plus";
import {copyObj, removeArrayItem} from "@/utils/libs";
import {Sortable} from "sortablejs"
import Compressor from "compressorjs";

const showDialog = ref(false)
const parentBorder = ref(true)
const childBorder = ref(true)
const tableData = ref([])
const sortedTableData = ref([])
const role = ref({context: []})
const formRef = ref(null)
const optTitle = ref("")
const loading = ref(true)

const rules = reactive({
  name: [{required: true, message: '请输入用户名', trigger: 'blur',}],
  key: [{required: true, message: '请输入应用标识', trigger: 'blur',}],
  icon: [{required: true, message: '请输入应用图标', trigger: 'blur',}],
  sort: [
    {required: true, message: '请输入排序数字', trigger: 'blur'},
    {type: 'number', message: '请输入有效数字'},
  ],
  hello_msg: [{required: true, message: '请输入打招呼信息', trigger: 'change',}]
})

const models = ref([])
onMounted(() => {
  fetchData()

  // get chat models
  httpGet('/api/admin/model/list?enable=1').then((res) => {
    models.value = res.data
  }).catch(() => {
    ElMessage.error("获取AI模型数据失败");
  })

})

const fetchData = () => {
  // 获取应用列表
  httpGet('/api/admin/role/list').then((res) => {
    tableData.value = res.data
    sortedTableData.value = copyObj(tableData.value)
    loading.value = false
  }).catch(() => {
    ElMessage.error("获取聊天应用失败");
  })

  const drawBodyWrapper = document.querySelector('.el-table__body tbody')
  // 初始化拖动排序插件
  Sortable.create(drawBodyWrapper, {
    sort: true,
    animation: 500,
    onEnd({newIndex, oldIndex, from}) {
      if (oldIndex === newIndex) {
        return
      }

      const sortedData = Array.from(from.children).map(row => row.querySelector('.sort').getAttribute('data-id'));
      const ids = []
      const sorts = []
      sortedData.forEach((id, index) => {
        ids.push(parseInt(id))
        sorts.push(index+1)
        tableData.value[index].sort_num = index + 1
      })

      httpPost("/api/admin/role/sort", {ids: ids, sorts: sorts}).catch(e => {
        ElMessage.error("排序失败：" + e.message)
      })
    }
  })
}

const roleSet = (filed, row) => {
  httpPost('/api/admin/role/set', {id: row.id, filed: filed, value: row[filed]}).then(() => {
    ElMessage.success("操作成功！")
  }).catch(e => {
    ElMessage.error("操作失败：" + e.message)
  })
}

// 编辑
const curIndex = ref(0)
const rowEdit = function (index, row) {
  optTitle.value = "修改应用"
  curIndex.value = index
  role.value = copyObj(row)
  showDialog.value = true
}

const addRole = function () {
  optTitle.value = "添加新应用"
  role.value = {context: []}
  showDialog.value = true
}

const save = function () {
  formRef.value.validate((valid) => {
    if (valid) {
      showDialog.value = false
      httpPost('/api/admin/role/save', role.value).then(() => {
        ElMessage.success('操作成功')
        fetchData()
      }).catch((e) => {
        ElMessage.error('操作失败，' + e.message)
      })
    }
  })
}

const removeRole = function (row) {
  httpGet('/api/admin/role/remove?id=' + row.id).then(() => {
    ElMessage.success("删除成功！")
    tableData.value = removeArrayItem(tableData.value, row, (v1, v2) => {
      return v1.id === v2.id
    })
  }).catch(() => {
    ElMessage.error("删除失败！")
  })
}

const addContext = function () {
  if (!role.value.context) {
    role.value.context = []
  }
  role.value.context.push({role: '', content: ''})
}

const removeContext = function (index) {
  role.value.context.splice(index, 1);
}

// 图片上传
const uploadImg = (file) => {
  // 压缩图片并上传
  new Compressor(file.file, {
    quality: 0.6,
    success(result) {
      const formData = new FormData();
      formData.append('file', result, result.name);
      // 执行上传操作
      httpPost('/api/admin/upload', formData).then((res) => {
        role.value.icon = res.data.url
        ElMessage.success('上传成功')
      }).catch((e) => {
        ElMessage.error('上传失败:' + e.message)
      })
    },
    error(e) {
      ElMessage.error('上传失败:' + e.message)
    },
  });
};
</script>

<style lang="stylus" scoped>
.role-list {
  .handle-box {
    margin-bottom 20px

    .handle-input {
      max-width 150px;
      margin-right 10px;
    }
  }

  .opt-box {
    padding-bottom: 10px;
    display flex;
    justify-content flex-end

    .el-icon {
      margin-right 5px;
    }
  }

  .context-msg-key {
    .fr {
      float right

      .el-icon {
        margin-right 5px
      }
    }
  }

  .context-msg-content {
    display flex

    .el-icon {
      font-size: 20px;
      margin-top 5px;
      margin-left 5px;
      cursor pointer
    }
  }

  .el-input--small {
    width 30px;

    .el-input__inner {
      text-align center
    }
  }

  .pagination {
    padding 20px 0
    display flex
    justify-content right
  }
}
</style>