GameView.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <template>
  2. <PagingTable url="/game" :where="where" ref="table">
  3. <template #filter>
  4. <ElButton :icon="Plus" @click="onEdit()">添加</ElButton>
  5. </template>
  6. <ElTableColumn prop="id" label="#" width="80" />
  7. <ElTableColumn prop="name" label="名称" min-width="120" />
  8. <ElTableColumn prop="status" label="状态" :formatter="statusFormatter" width="120" />
  9. <ElTableColumn prop="createdAt" label="创建时间" :formatter="timeFormatter" width="150" />
  10. <ElTableColumn label="操作" align="center" width="350">
  11. <template #default="{ row }">
  12. <ElButton @click="onPlay(row)" type="primary">进入</ElButton>
  13. <ElButton @click="onEdit(row)">编辑</ElButton>
  14. <ElButton @click="bindTwitch(row)" type="success">绑定Twitch</ElButton>
  15. <ElButton @click="onDelete(row)" type="danger">删除</ElButton>
  16. </template>
  17. </ElTableColumn>
  18. </PagingTable>
  19. <EditDialog
  20. v-model="showEditDialog"
  21. :model="model"
  22. :rules="rules"
  23. :on-submit="submit"
  24. @success="table.refresh()"
  25. width="800px"
  26. >
  27. <ElFormItem prop="name" label="名称">
  28. <ElInput v-model="model.name" placeholder="请输入名称" />
  29. </ElFormItem>
  30. <ElFormItem prop="roomId" label="房间ID">
  31. <ElInput v-model="model.roomId" placeholder="请输入房间ID" />
  32. </ElFormItem>
  33. <ElFormItem prop="background" label="故事背景">
  34. <ElInput v-model="model.background" type="textarea" placeholder="请输入故事背景" />
  35. </ElFormItem>
  36. <ElFormItem prop="charactors" label="初始角色">
  37. <div class="charactor-form" v-for="(item, i) in model.charactors" :key="i">
  38. <ElForm :model="item" label-position="top" inline :rules="charactorRules" ref="charactorForms">
  39. <ElFormItem prop="name" label="角色名称">
  40. <ElInput v-model="item.name" />
  41. </ElFormItem>
  42. <ElFormItem prop="gender" label="性别">
  43. <ElInput v-model="item.gender" />
  44. </ElFormItem>
  45. <ElFormItem prop="age" label="年龄">
  46. <ElInput v-model="item.age" />
  47. </ElFormItem>
  48. <ElFormItem prop="occupation" label="职业">
  49. <ElInput v-model="item.occupation" />
  50. </ElFormItem>
  51. <ElFormItem prop="personality" label="性格">
  52. <ElInput v-model="item.personality" />
  53. </ElFormItem>
  54. <div class="w-full"></div>
  55. <ElFormItem class="w-full" prop="background" label="背景">
  56. <ElInput v-model="item.background" type="textarea" />
  57. </ElFormItem>
  58. </ElForm>
  59. <ElButton type="danger" size="small" @click="removeCharactor(i)">删除</ElButton>
  60. </div>
  61. <ElButton @click="genCharactor" :loading="generating">生成</ElButton>
  62. <ElButton @click="onAddCharactor">添加</ElButton>
  63. </ElFormItem>
  64. </EditDialog>
  65. </template>
  66. <script setup>
  67. import { ref } from 'vue'
  68. import PagingTable from '@/components/PagingTable.vue'
  69. import { useEnumFormatter, useTimeFormatter } from '@/utils/formatter'
  70. import { Plus } from '@vicons/tabler'
  71. import EditDialog from '@/components/EditDialog.vue'
  72. import { setupEditDialog } from '@/utils/editDialog'
  73. import EnumSelect from '@/components/EnumSelect.vue'
  74. import { GameStatus } from '@/enums'
  75. import { http } from '@/plugins/http'
  76. import { ElMessage, ElMessageBox } from 'element-plus'
  77. import { useClipboard } from '@vueuse/core'
  78. import { useRouter } from 'vue-router'
  79. const router = useRouter()
  80. const where = ref({})
  81. const timeFormatter = useTimeFormatter()
  82. const statusFormatter = useEnumFormatter(GameStatus)
  83. const table = ref(null)
  84. const model = ref({})
  85. const rules = {
  86. name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
  87. roomId: [{ required: true, message: '请输入房间ID', trigger: 'blur' }],
  88. background: [{ required: true, message: '请输入故事背景', trigger: 'blur' }],
  89. charactors: [
  90. {
  91. validator: (rule, value, callback) => {
  92. if (!value || value.length === 0) {
  93. callback(new Error('请输入初始角色'))
  94. } else {
  95. Promise.all(charactorForms.value.map((form) => form.validate()))
  96. .then(() => {
  97. callback()
  98. })
  99. .catch(() => {
  100. callback(new Error('请输入初始角色'))
  101. })
  102. }
  103. }
  104. }
  105. ]
  106. }
  107. const { showEditDialog, onEdit } = setupEditDialog(model)
  108. async function submit() {
  109. await http.put(model.value.id ? `/game/${model.value.id}` : '/game', model.value)
  110. ElMessage.success('保存成功')
  111. }
  112. async function onDelete(row) {
  113. await ElMessageBox.confirm('确认删除?', '删除', { type: 'warning' })
  114. await http.delete(`/game/${row.id}`)
  115. ElMessage.success('删除成功')
  116. table.value.refresh()
  117. }
  118. const generating = ref(false)
  119. async function genCharactor() {
  120. const { value } = await ElMessageBox.prompt('生成数量:', '生成角色', {
  121. inputPattern: /^\d{1,2}$/,
  122. inputErrorMessage: 'Invalid Num'
  123. })
  124. generating.value = true
  125. try {
  126. const res = await http.post(`/game/${model.value.id}/genCharactor`, { gameId: model.value.id, num: value })
  127. generating.value = false
  128. model.value.charactors = (model.value.charactors || []).concat(res)
  129. } catch (error) {
  130. ElMessage.error(error.message)
  131. generating.value = false
  132. }
  133. }
  134. function onAddCharactor() {
  135. model.value.charactors = (model.value.charactors || []).concat({})
  136. }
  137. const charactorRules = {
  138. name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
  139. gender: [{ required: true, message: '请输入性别', trigger: 'blur' }],
  140. age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
  141. occupation: [{ required: true, message: '请输入职业', trigger: 'blur' }],
  142. personality: [{ required: true, message: '请输入性格', trigger: 'blur' }],
  143. background: [{ required: true, message: '请输入背景', trigger: 'blur' }]
  144. }
  145. const charactorForms = ref([])
  146. function removeCharactor(index) {
  147. model.value.charactors.splice(index, 1)
  148. }
  149. function onPlay(row) {
  150. router.push({
  151. name: 'play',
  152. params: {
  153. id: row.id
  154. }
  155. })
  156. }
  157. function bindTwitch(row) {
  158. let u = new URL('https://id.twitch.tv/oauth2/authorize?')
  159. u.searchParams.append('client_id', '530df6x09eq34be0vjhsezkl2oxap0')
  160. u.searchParams.append('redirect_uri', 'http://localhost:3000/api/twitch/auth_callback')
  161. u.searchParams.append('response_type', 'code')
  162. u.searchParams.append('xxx', 'aaa')
  163. u.searchParams.append('scope', 'channel:manage:broadcast chat:read chat:edit channel:manage:polls')
  164. window.open(u.href)
  165. }
  166. </script>
  167. <style lang="less" scoped>
  168. .charactor-form {
  169. background-color: var(--el-color-info-light-9);
  170. padding: 15px;
  171. border-radius: 8px;
  172. margin-bottom: 10px;
  173. .el-form-item {
  174. margin-bottom: 20px;
  175. }
  176. }
  177. </style>