useWeMenu.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import { useAjax } from '@/Hook/useAjax'
  2. import { delMenu, editMenu, getMenu, syncMenu, syncPlatform } from '@/services/operating/weMenu'
  3. import { useCallback, useReducer } from 'react'
  4. type State = {
  5. defaultMenu: any,//菜单配置
  6. resMenu: any,//默认菜单配置 作比较使用
  7. conditionalMenus: any[],//个性菜单
  8. actionMenuId?: number,//当前选中的菜单ID
  9. actionItemId?: number,//当前选中的子菜单ID
  10. msgVisible: boolean,//图片,视频,音频类型弹窗
  11. textVisible: boolean,//文字类型弹窗
  12. graphicVisible: boolean,//图文类型弹窗
  13. imgCardVisible: boolean,//小程序卡片弹窗
  14. msgType: 'news' | 'text' | 'voice' | 'video' | 'image',//消息类型
  15. actionWX: any,//选中微信
  16. theEdit: any,//选中的数据
  17. type: 'click' | 'view' | 'miniprogram',//菜单按钮类型
  18. ref: any,
  19. // ruleClientPlatformType: null | '1' | '2'//公众号菜单类型1:IOS 2安卓 NULL默认
  20. addMenuType: '0' | '1' | '2',//新增类型菜单
  21. isSaver: boolean//是否保存
  22. isUserId: any//是否在路径中插入userID 1|0
  23. }
  24. export type Action = {
  25. type: 'addMenu' | 'moveAddMenu' | 'addMenuItem' | 'moveAddMenuItem' | 'actionMenuId'
  26. | 'actionItemId' | 'msgType' | 'msgVisible' |
  27. 'textVisible' | 'graphicVisible' | 'theEdit' |
  28. 'setMenuType' | 'initData' | 'delMenu' |
  29. 'setName' | 'defaultData' | 'setRef' | 'pushData' | 'isSaver' | 'init' |
  30. 'addConditionalMenus' | 'addMenuType' | 'ruleClientPlatformType' | 'imgCardVisible' | 'isUserId'
  31. params?: any
  32. }
  33. export function reducer(state: State, action: Action) {
  34. let { type, params } = action
  35. let { actionMenuId, actionItemId } = state
  36. let newMenu: any = {}
  37. switch (type) {
  38. case 'moveAddMenu':
  39. return { ...state, defaultMenu: params.defaultMenu }
  40. case 'actionMenuId'://选中的菜单当选中菜单ID把子菜单选中ID设为0,为了配合选中效果逻辑
  41. return { ...state, actionMenuId: params.actionMenuId, actionItemId: 0, }
  42. case 'actionItemId'://选中的菜单子菜单
  43. return { ...state, actionItemId: params.actionItemId, }
  44. case 'addMenu'://添加菜单
  45. newMenu = JSON.parse(JSON.stringify(state.defaultMenu))
  46. if (newMenu?.buttons?.length < 4) {
  47. //假如subMenus的长度大于0,那么已存至少一个菜单,那新增的菜单menuId就按第一个菜单的menuId+1 否则就是第一次添加
  48. newMenu?.buttons?.push({ menuId: newMenu?.buttons?.length > 0 ? newMenu?.buttons[newMenu?.buttons?.length - 1].menuId + 1 : 1, subButtons: [], type: 'click' })
  49. state.actionMenuId = newMenu?.buttons?.length > 0 ? newMenu?.buttons[newMenu?.buttons?.length - 1].menuId : 1
  50. }
  51. return { ...state, defaultMenu: newMenu, isSaver: false }
  52. case 'addMenuItem'://添加子菜单
  53. newMenu = JSON.parse(JSON.stringify(state.defaultMenu))
  54. let itemArr: any = [];
  55. newMenu?.buttons?.map((item: any) => {//遍历菜单查找菜单ID是否等于选中的菜单ID,是就把当前菜单的子菜单数组赋值给变量itemArr
  56. if (item.menuId === state.actionMenuId) {
  57. itemArr = item.subButtons
  58. }
  59. })
  60. if (itemArr.length < 6) {//假如itemArr的长度小于6证明不满5个可以添加子菜单,子菜单的ID等于菜单长度+1
  61. //假如itemArr的长度大于0,那么已存至少一个子菜单,那新增的子菜单itemId就按第一个菜单的itemId+1 否则就是第一次添加
  62. itemArr.push({ itemId: itemArr.length > 0 ? itemArr[itemArr.length - 1].itemId + 1 : 1, type: 'click' })
  63. state.actionItemId = itemArr.length > 0 ? itemArr[itemArr.length - 1].itemId : 1
  64. }
  65. newMenu?.buttons?.forEach((item: any) => {//最后将编辑后的itemArr数组放回当前选中的菜单中,返回整个state页面监听到参数有改动重新渲染
  66. if (item.menuId === state.actionMenuId) {
  67. //添加子菜单清空父菜单多余内容
  68. item.subButtons = itemArr
  69. item.url = ''
  70. item.appId = ''
  71. item.pagePath = ''
  72. item.menuType = ''
  73. item.msgContent = {}
  74. }
  75. })
  76. return { ...state, defaultMenu: newMenu, isSaver: false }
  77. case 'delMenu':
  78. let { menuId, itemId } = params
  79. newMenu = JSON.parse(JSON.stringify(state.defaultMenu))
  80. if (menuId && !itemId) {//menuId存在,itemId不存在删除主菜单
  81. newMenu.buttons = newMenu?.buttons?.filter((item: any) => {
  82. if (item.menuId !== menuId) {
  83. return item
  84. }
  85. })
  86. //处理menuId不然选中会错乱
  87. newMenu.buttons = newMenu?.buttons?.map((item: any, index: number) => {
  88. item.menuId = index + 1
  89. return item
  90. })
  91. //删除主菜单清除选中的主菜单ID
  92. newMenu = { actionMenuId: menuId && !itemId ? 0 : actionMenuId, defaultMenu: newMenu }
  93. }
  94. if (menuId && itemId) { //menuId, itemId 都存在删除子菜单
  95. newMenu.buttons = newMenu?.buttons?.map((item: any) => {
  96. if (item.menuId === menuId) {//遍历菜单数组查找当前选中的主菜单
  97. item.subButtons = item.subButtons.filter((items: any) => {//筛选子菜单
  98. if (items.itemId !== itemId) {
  99. return items
  100. }
  101. })
  102. if (item.subButtons.length === 0) {//假如删完了子菜单给父菜单添加type
  103. item.type = 'click'
  104. }
  105. return item
  106. }
  107. return item
  108. })
  109. //删除子菜单清除选中的子菜单ID归0选中调回主菜单
  110. newMenu = { actionMenuId: actionMenuId, actionItemId: 0, defaultMenu: newMenu }
  111. }
  112. return { ...state, ...newMenu, isSaver: JSON.stringify(state.resMenu) === JSON.stringify(newMenu.defaultMenu) }
  113. case 'msgType':
  114. return { ...state, msgType: params.msgType }
  115. case 'setMenuType':
  116. return { ...state, menuType: params.menuType }
  117. case 'msgVisible':
  118. return { ...state, msgVisible: !state.msgVisible }
  119. case 'textVisible':
  120. return { ...state, textVisible: !state.textVisible }
  121. case 'graphicVisible':
  122. return { ...state, graphicVisible: !state.graphicVisible }
  123. case 'imgCardVisible':
  124. return { ...state, imgCardVisible: !state.imgCardVisible }
  125. case 'theEdit':
  126. return { ...state, theEdit: params.theEdit }
  127. case 'addConditionalMenus':
  128. let conditionalMenus
  129. if(params?.ruleClientPlatformType === 0){
  130. conditionalMenus = [...state.conditionalMenus, { buttons: [] }]
  131. }else{
  132. conditionalMenus = state.conditionalMenus.length < 3 ? [...state.conditionalMenus, { buttons: [], ruleClientPlatformType: params.ruleClientPlatformType }] : state.conditionalMenus
  133. }
  134. return { ...state, conditionalMenus }
  135. case 'addMenuType':
  136. return { ...state, addMenuType: params.addMenuType }
  137. case 'ruleClientPlatformType':
  138. return { ...state, defaultMenu: { ...state.defaultMenu, ruleClientPlatformType: params.ruleClientPlatformType }, isSaver: false }
  139. case 'isUserId':
  140. return { ...state, isUserId: params.isUserId }
  141. case 'pushData':
  142. newMenu = JSON.parse(JSON.stringify(state.defaultMenu))
  143. Object.keys(params).forEach((key: string) => {
  144. newMenu?.buttons?.map((item: any) => {
  145. if (actionMenuId && !actionItemId) {
  146. if (item.menuId === actionMenuId) {
  147. if (key === 'msgType') {
  148. item.msgContent[key] = params[key]
  149. } else {
  150. item[key] = params[key]
  151. }
  152. }
  153. }
  154. if (actionMenuId && actionItemId && item?.subButtons?.length > 0) {
  155. if (item.menuId === actionMenuId) {
  156. item.subButtons.map((button: any) => {
  157. if (button.itemId === actionItemId) {
  158. if (key === 'msgType') {
  159. } else {
  160. button[key] = params[key]
  161. }
  162. }
  163. })
  164. }
  165. }
  166. })
  167. })
  168. return { ...state, defaultMenu: newMenu, isSaver: false }
  169. case 'initData'://清空内容
  170. return { ...initData, defaultMenu: state.defaultMenu, actionItemId, actionMenuId, conditionalMenus: state.conditionalMenus, resMenu: state.resMenu, addMenuType: state.addMenuType }
  171. case 'defaultData'://回填接口获取的菜单
  172. return { ...initData, conditionalMenus: params.conditionalMenus, defaultMenu: params.defaultMenu, resMenu: params.resMenu }
  173. case 'init':
  174. return { ...initData }
  175. case 'setRef':
  176. return { ...state, ref: params.ref }
  177. case 'isSaver':
  178. return { ...state, isSaver: true }
  179. default:
  180. return state;
  181. }
  182. }
  183. let initData: State = {
  184. defaultMenu: { ruleClientPlatformType: null, buttons: [] },
  185. resMenu: {},
  186. conditionalMenus: [],
  187. msgType: 'news',
  188. msgVisible: false,
  189. textVisible: false,
  190. graphicVisible: false,
  191. theEdit: null,
  192. actionWX: null,
  193. type: 'click',
  194. ref: null,
  195. addMenuType: '0',
  196. isSaver: true,
  197. imgCardVisible: false,
  198. isUserId: 1
  199. }
  200. export default function useWeMenu() {
  201. const [state, dispatch] = useReducer(reducer, initData)
  202. const getMenus = useAjax((params: { mpId: string }) => getMenu(params))
  203. const delMenus = useAjax((params: { menuId: string }) => delMenu(params), { msgNmae: '删除' })
  204. const editMenus = useAjax((params: any) => editMenu(params), { msgNmae: '编辑' })
  205. const syncMenus = useAjax((params: { mpId: string }) => syncMenu(params), { msgNmae: '同步' })
  206. const syncPlatforms = useAjax((params: { platform: string, menuId: string }) => syncPlatform(params), { msgNmae: '同步' })
  207. const addMenu = useCallback(() => {
  208. console.log('11111')
  209. dispatch({ type: 'initData' })//清空数据初始化只保留已编辑的菜单
  210. dispatch({ type: 'addMenu' })
  211. }, [])
  212. const setMenuId = useCallback((actionMenuId: number) => {
  213. dispatch({ type: 'actionMenuId', params: { actionMenuId } })
  214. }, [])
  215. const setItemId = useCallback((actionItemId: number) => {
  216. dispatch({ type: 'actionItemId', params: { actionItemId } })
  217. }, [])
  218. const addMenuItem = useCallback(() => {
  219. dispatch({ type: 'initData' })//清空数据初始化只保留已编辑的数组
  220. dispatch({ type: 'addMenuItem' }) //添加一级菜单
  221. }, [])
  222. return {
  223. state,
  224. addMenu,
  225. setMenuId,
  226. setItemId,
  227. addMenuItem,
  228. getMenus,
  229. delMenus,
  230. editMenus,
  231. syncMenus,
  232. dispatch,
  233. syncPlatforms
  234. }
  235. }