|
| 1 | +<template> |
| 2 | + <b-container |
| 3 | + class="mx-0 px-0" |
| 4 | + fluid |
| 5 | + > |
| 6 | + <b-row> |
| 7 | + <b-col> |
| 8 | + <div |
| 9 | + v-if="!loaded" |
| 10 | + class="text-center center-spinner" |
| 11 | + > |
| 12 | + <b-spinner |
| 13 | + style="width: 10rem; height: 10rem;" |
| 14 | + variant="info" |
| 15 | + /> |
| 16 | + </div> |
| 17 | + <template v-else-if="sortedScenes.length > 0"> |
| 18 | + <b-table |
| 19 | + :items="tableData" |
| 20 | + :fields="tableFields" |
| 21 | + responsive |
| 22 | + show-empty |
| 23 | + sticky-header="65vh" |
| 24 | + > |
| 25 | + <template #thead-top="data"> |
| 26 | + <b-tr> |
| 27 | + <b-th colspan="1"> |
| 28 | + <span class="sr-only">Character</span> |
| 29 | + </b-th> |
| 30 | + <template v-for="act in sortedActs"> |
| 31 | + <b-th |
| 32 | + v-if="numScenesPerAct(act.id) > 0" |
| 33 | + :key="act.id" |
| 34 | + variant="primary" |
| 35 | + :colspan="numScenesPerAct(act.id)" |
| 36 | + class="act-header" |
| 37 | + > |
| 38 | + {{ act.name }} |
| 39 | + </b-th> |
| 40 | + </template> |
| 41 | + </b-tr> |
| 42 | + </template> |
| 43 | + <template |
| 44 | + v-for="scene in sortedScenes" |
| 45 | + #[getHeaderName(scene.id)]="data" |
| 46 | + > |
| 47 | + {{ scene.name }} |
| 48 | + </template> |
| 49 | + <template #cell(Character)="data"> |
| 50 | + {{ CHARACTER_BY_ID(data.item.Character).name }} |
| 51 | + </template> |
| 52 | + <template |
| 53 | + v-for="scene in sortedScenes" |
| 54 | + #[getCellName(scene.id)]="data" |
| 55 | + > |
| 56 | + <template |
| 57 | + v-if="getLineCountForCharacter(data.item.Character, scene.act, scene.id) > 0" |
| 58 | + > |
| 59 | + {{ getLineCountForCharacter(data.item.Character, scene.act, scene.id) }} |
| 60 | + </template> |
| 61 | + </template> |
| 62 | + </b-table> |
| 63 | + </template> |
| 64 | + <b v-else>Unable to get mic allocations. Ensure act and scene ordering is set.</b> |
| 65 | + </b-col> |
| 66 | + </b-row> |
| 67 | + </b-container> |
| 68 | +</template> |
| 69 | + |
| 70 | +<script> |
| 71 | +import { mapActions, mapGetters } from 'vuex'; |
| 72 | +import { makeURL } from '@/js/utils'; |
| 73 | +import log from 'loglevel'; |
| 74 | +
|
| 75 | +export default { |
| 76 | + name: 'CharacterLineStats', |
| 77 | + data() { |
| 78 | + return { |
| 79 | + loaded: false, |
| 80 | + characterStats: {}, |
| 81 | + }; |
| 82 | + }, |
| 83 | + async mounted() { |
| 84 | + await this.GET_ACT_LIST(); |
| 85 | + await this.GET_SCENE_LIST(); |
| 86 | + await this.getCharacterStats(); |
| 87 | + this.loaded = true; |
| 88 | + }, |
| 89 | + methods: { |
| 90 | + numScenesPerAct(actId) { |
| 91 | + return this.sortedScenes.filter((scene) => scene.act === actId).length; |
| 92 | + }, |
| 93 | + getHeaderName(sceneId) { |
| 94 | + return `head(${sceneId})`; |
| 95 | + }, |
| 96 | + getCellName(sceneId) { |
| 97 | + return `cell(${sceneId})`; |
| 98 | + }, |
| 99 | + async getCharacterStats() { |
| 100 | + const response = await fetch(`${makeURL('/api/v1/show/character/stats')}`); |
| 101 | + if (response.ok) { |
| 102 | + this.characterStats = await response.json(); |
| 103 | + } else { |
| 104 | + log.error('Unable to get character stats!'); |
| 105 | + } |
| 106 | + }, |
| 107 | + getLineCountForCharacter(characterId, actId, sceneId) { |
| 108 | + if (!Object.keys(this.characterStats).includes('line_counts')) { |
| 109 | + return 0; |
| 110 | + } |
| 111 | + const lineCounts = this.characterStats.line_counts; |
| 112 | + if (Object.keys(lineCounts).includes(characterId.toString())) { |
| 113 | + const characterCounts = this.characterStats.line_counts[characterId]; |
| 114 | + if (Object.keys(characterCounts).includes(actId.toString())) { |
| 115 | + const actCounts = characterCounts[actId]; |
| 116 | + if (Object.keys(actCounts).includes(sceneId.toString())) { |
| 117 | + return actCounts[sceneId]; |
| 118 | + } |
| 119 | + } |
| 120 | + } |
| 121 | + return 0; |
| 122 | + }, |
| 123 | + ...mapActions(['GET_ACT_LIST', 'GET_SCENE_LIST']), |
| 124 | + }, |
| 125 | + computed: { |
| 126 | + tableData() { |
| 127 | + if (!this.loaded) { |
| 128 | + return []; |
| 129 | + } |
| 130 | + return this.CHARACTER_LIST.map((character) => ({ |
| 131 | + Character: character.id, |
| 132 | + }), this); |
| 133 | + }, |
| 134 | + tableFields() { |
| 135 | + return ['Character', ...this.sortedScenes.map((scene) => (scene.id.toString()))]; |
| 136 | + }, |
| 137 | + sortedActs() { |
| 138 | + if (this.CURRENT_SHOW.first_act_id == null) { |
| 139 | + return []; |
| 140 | + } |
| 141 | + let currentAct = this.ACT_BY_ID(this.CURRENT_SHOW.first_act_id); |
| 142 | + if (currentAct == null) { |
| 143 | + return []; |
| 144 | + } |
| 145 | + const acts = []; |
| 146 | + while (currentAct != null) { |
| 147 | + acts.push(currentAct); |
| 148 | + currentAct = this.ACT_BY_ID(currentAct.next_act); |
| 149 | + } |
| 150 | + return acts; |
| 151 | + }, |
| 152 | + sortedScenes() { |
| 153 | + if (this.CURRENT_SHOW.first_act_id == null) { |
| 154 | + return []; |
| 155 | + } |
| 156 | +
|
| 157 | + let currentAct = this.ACT_BY_ID(this.CURRENT_SHOW.first_act_id); |
| 158 | + if (currentAct == null || currentAct.first_scene == null) { |
| 159 | + return []; |
| 160 | + } |
| 161 | +
|
| 162 | + const scenes = []; |
| 163 | + while (currentAct != null) { |
| 164 | + let currentScene = this.SCENE_BY_ID(currentAct.first_scene); |
| 165 | + while (currentScene != null) { |
| 166 | + scenes.push(currentScene); |
| 167 | + currentScene = this.SCENE_BY_ID(currentScene.next_scene); |
| 168 | + } |
| 169 | + currentAct = this.ACT_BY_ID(currentAct.next_act); |
| 170 | + } |
| 171 | + return scenes; |
| 172 | + }, |
| 173 | + ...mapGetters(['ACT_BY_ID', 'SCENE_BY_ID', 'CURRENT_SHOW', 'CHARACTER_BY_ID', 'CHARACTER_LIST']), |
| 174 | + }, |
| 175 | +}; |
| 176 | +</script> |
0 commit comments