index.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <template>
  2. <CommonPage>
  3. <template #action>
  4. <NButton type="primary" @click="router.push('article/add')">
  5. <i class="i-material-symbols:add mr-4 text-18" />
  6. 新增文章
  7. </NButton>
  8. </template>
  9. <MeCrud ref="$table" v-model:query-items="queryItems" :scroll-x="1200" :columns="columns" :get-data="api.read">
  10. <MeQueryItem label="标题" :label-width="50">
  11. <n-input v-model:value="queryItems.title" type="text" placeholder="请输入标题" clearable>
  12. <template #password-visible-icon />
  13. </n-input>
  14. </MeQueryItem>
  15. <MeQueryItem label="状态" :label-width="50">
  16. <n-select v-model:value="queryItems.enable" clearable :options="[
  17. { label: '启用', value: 1 },
  18. { label: '停用', value: 0 },
  19. ]" />
  20. </MeQueryItem>
  21. </MeCrud>
  22. </CommonPage>
  23. </template>
  24. <script setup>
  25. import { MeCrud, MeQueryItem } from '@/components'
  26. import { useCrud } from '@/composables'
  27. import { formatDateTime } from '@/utils'
  28. import { NButton, NSwitch, NDropdown } from 'naive-ui'
  29. import api from './api'
  30. defineOptions({ name: 'RoleMgt' })
  31. const router = useRouter()
  32. const $table = ref(null)
  33. /** QueryBar筛选参数(可选) */
  34. const queryItems = ref({})
  35. onMounted(() => {
  36. $table.value?.handleSearch()
  37. })
  38. const { handleDelete }
  39. = useCrud({
  40. name: '文章',
  41. doCreate: api.create,
  42. doDelete: api.delete,
  43. doUpdate: api.update,
  44. initForm: { enable: true },
  45. refresh: (_, keepCurrentPage) => $table.value?.handleSearch(keepCurrentPage),
  46. })
  47. const topOptions = [
  48. {
  49. label: '设置置顶',
  50. key: 'up',
  51. },
  52. {
  53. label: '取消置顶',
  54. key: 'down',
  55. }
  56. ]
  57. const columns = [
  58. { title: 'ID', key: 'id', width: '80' },
  59. { title: '标题', key: 'title', width: '200' },
  60. { title: '分类', key: 'category.title' },
  61. {
  62. title: '内容',
  63. key: 'content',
  64. width: '400',
  65. render: row => h('div', htmlspecialchars(row.translations?.length ? row.translations.find(i => i.locale === 'zh').content : row.content)),
  66. },
  67. { title: '创建人', key: 'user.username' },
  68. {
  69. title: '创建时间',
  70. key: 'createTime',
  71. render: row => h('span', formatDateTime(row.createTime)),
  72. },
  73. {
  74. title: '状态',
  75. key: 'enable',
  76. render: row =>
  77. h(
  78. NSwitch,
  79. {
  80. size: 'small',
  81. rubberBand: false,
  82. value: row.enable,
  83. loading: !!row.enableLoading,
  84. disabled: row.code === 'SUPER_ADMIN',
  85. onUpdateValue: () => handleEnable(row),
  86. },
  87. {
  88. checked: () => '启用',
  89. unchecked: () => '停用',
  90. },
  91. ),
  92. },
  93. {
  94. title: '操作',
  95. key: 'actions',
  96. //width: 200,
  97. align: 'center',
  98. fixed: 'right',
  99. render(row) {
  100. return [
  101. h(NDropdown, {
  102. options:topOptions,
  103. trigger: 'click',
  104. onSelect: (key) => handleUpDown(row,key)
  105. }, {
  106. default: () => h(NButton,
  107. {
  108. bordered: false,
  109. type: 'info',
  110. size: "small"
  111. },
  112. {
  113. default: () => '置顶',
  114. // icon: () => h('i', { class: 'i-fe:more-horizontal mr-4 text-16' }),
  115. })
  116. }),
  117. h(
  118. NButton,
  119. {
  120. size: 'small',
  121. type: 'primary',
  122. style: 'margin-left: 6px;margin-right: 6px;',
  123. disabled: row.code === 'SUPER_ADMIN',
  124. onClick: () => handleEdit(row),
  125. },
  126. {
  127. default: () => '编辑',
  128. // icon: () => h('i', { class: 'i-material-symbols:edit-outline text-14' }),
  129. },
  130. ),
  131. h(
  132. NButton,
  133. {
  134. size: 'small',
  135. type: 'error',
  136. disabled: row.code === 'SUPER_ADMIN',
  137. onClick: () => handleDelete(row.id),
  138. },
  139. {
  140. default: () => '删除',
  141. // icon: () => h('i', { class: 'i-material-symbols:delete-outline text-14' }),
  142. },
  143. ),
  144. ]
  145. },
  146. },
  147. ]
  148. async function handleEnable(row) {
  149. row.enableLoading = true
  150. try {
  151. console.log('row', row)
  152. await api.update({ ...row, id: row.id, enable: !row.enable })
  153. row.enableLoading = false
  154. $message.success('操作成功')
  155. $table.value?.handleSearch()
  156. }
  157. catch (error) {
  158. console.error(error)
  159. row.enableLoading = false
  160. }
  161. }
  162. function htmlspecialchars(str) {
  163. const div = document.createElement('div')
  164. div.innerHTML = str
  165. const text = div.textContent || ''
  166. return text.length > 150 ? `${text.substring(0, 150)}...` : text
  167. }
  168. function handleEdit(row) {
  169. router.push(`/article/edit/${row.id}`)
  170. }
  171. async function handleUpDown(row,key) {
  172. row.enableLoading = true
  173. try {
  174. if(key == 'up') {
  175. await api.up(row.id)
  176. } else {
  177. await api.down(row.id)
  178. }
  179. row.enableLoading = false
  180. $message.success('操作成功')
  181. $table.value?.handleSearch()
  182. }
  183. catch (error) {
  184. console.error(error)
  185. row.enableLoading = false
  186. }
  187. }
  188. </script>